Kate’s DVG code
message("Loading packages")
Loading packages
library('ggplot2')
library('readr')
library('reshape2')
library('ggpubr')
library('plyr')
library('tidyverse')
library('dplyr')
library('glue')
library('ggVennDiagram')
# paramters used when running divrge
grouping_param = 5
match_length_param = 28
readLength = 150
# deletion read count cutoffs
count_cut = 30
message("Setting work directory and input file names")
Setting work directory and input file names
wkdir = "/Users/marissaknoll/Desktop/GitHub/Obesity/NewExtractions/H9N2/DVGs"
setwd(wkdir)
if (!dir.exists(glue("{wkdir}/DVG_figures"))) {
dir.create(glue("{wkdir}/DVG_figures"))
}
saveitdir = glue("{wkdir}/DVG_figures")
source(glue('{wkdir}/scripts/obese_PlotPrep.R'))
# loading in metadata and coverage data
metafile = glue("{wkdir}/../H9_Metadata.csv")
meta = read.csv(file=metafile,header=T,sep=",",na.strings = c(''))
meta = filter(meta, resequenced == "yes") %>% filter(cohort != "ND")
transmission_info = "/Users/marissaknoll/Desktop/GitHub/Obesity/NewExtractions/H9N2/TransmissionPairs.csv"
pairs = read.csv(transmission_info, header = T)
meta = merge(meta, pairs, all.x = TRUE) %>% unique()
coverage_passfile = glue('{wkdir}/scripts/H9N2.coverage.pass.check.200.0.95.csv')
cov_check = read.csv(file=coverage_passfile,header=T,sep=",",na.strings = c(''))
# filter for samples that either pass with a yes OR has good average coverage and percentage cov at 200x is > 80
cov_filt_names = cov_check %>% filter(pass == 'YES' |
mean_coverage >= 200 |
percentage > 0.4) %>%
select(name, segment) %>%
unique()
# check segment count
cov_filt_names = cov_filt_names %>% group_by(name) %>% add_tally(name = 'segment_tally') %>%
ungroup() %>%
filter(segment_tally == 8) %>%
unique()
pull_names = c(levels(factor(cov_filt_names$name))) # list to pull names from
dvgfile = glue('{wkdir}/H9N2.DVG.FINAL.OneGap.N5.Mis2.M28.G5.csv') # dvg file
dvg = read.csv(file=dvgfile,header=T,sep=",",na.strings = c(''))
dvg = dvg %>% filter(name %in% pull_names) # filter for samples that pass our coverage checks
dvg$sample = dvg$name # generate new column so we can separate
dvg = dvg %>% separate(sample, c('new','cohort','ferret_id','dpi','rep'), '_') # separate into info
Warning: Expected 5 pieces. Missing pieces filled with `NA` in 40841 rows [200561, 200562, 200563, 200564, 200565, 200566, 200567, 200568, 200569, 200570, 200571, 200572, 200573, 200574, 200575, 200576, 200577, 200578, 200579, 200580, ...].
CONTROLS = dvg %>% filter(ferret_id == 'HK1073') # pulling out controls
CONTROLS$rep = CONTROLS$dpi
CONTROLS$dpi = 'stock' # adding in stock info
dvg = dvg %>% filter(!name %in% c(levels(factor(CONTROLS$name)))) %>% unique()
dvg = rbind(dvg, CONTROLS) # rbind everything so it is all in one dataframe
# prepping rep information
dvg = dvg %>% select(-SegTotalDVG, -new) %>% filter(DVG_freq >= count_cut) %>% unique() # filter for those that pass cutoffs
rep1 = dvg %>% filter(rep == 'rep1') %>% unique()
rep2 = dvg %>% filter(rep == 'rep2') %>% unique()
# merge reps into one
dvg_reps = merge(rep1, rep2, by = c('cohort','ferret_id','dpi',
'segment','segment_size','strain',
'DVG_group','NewGap',
'NewStart','NewEnd','GroupBoundaries',
'DeletionSize','EstimatedFragLength'), all = TRUE) %>% unique()
# add in zeros
dvg_reps$DVG_freq.x[is.na(dvg_reps$DVG_freq.x)] = 0
dvg_reps$DVG_freq.y[is.na(dvg_reps$DVG_freq.y)] = 0
ggplot(dvg_reps, aes(x=DVG_freq.x, y=DVG_freq.y)) +
geom_point() +
PlotTheme1

# number of samples?
levels(factor(dvg_reps$ferret_id)) %>% length()
[1] 42
# reorder by segment size
SEGMENTS = c('H9N2_PB2', 'H9N2_PB1',
'H9N2_PA','H9N2_HA','H9N2_NP',
'H9N2_NA','H9N2_MP','H9N2_NS')
cov_check$segment = factor(cov_check$segment, levels = SEGMENTS)
cov_check %>%
filter(name %in% pull_names) %>%
ggplot(., aes(x= segment, y = mean_coverage)) +
geom_boxplot() +
PlotTheme1

cov_check %>%
filter(name %in% pull_names) %>%
ggplot(., aes(x= segment, y = median_coverage)) +
geom_boxplot() +
PlotTheme1

cov_check %>%
filter(name %in% pull_names) %>%
ggplot(., aes(x= segment, y = percentage)) +
geom_boxplot() +
PlotTheme1

df = cov_filt_names %>% select(-segment, -segment_tally) %>% unique()
df$sample = df$name
df = df %>% separate(sample, c('new','cohort','ferret_id','dpi','rep'), '_')
Warning: Expected 5 pieces. Missing pieces filled with `NA` in 10 rows [35, 36, 50, 72, 85, 154, 166, 171, 188, 202].
CONTROLS = df %>% filter(ferret_id == 'HK1073')
CONTROLS$rep = CONTROLS$dpi
CONTROLS$dpi = 'stock'
df = df %>% filter(!name %in% c(levels(factor(CONTROLS$name)))) %>% unique()
df = rbind(df, CONTROLS)
r1 = df %>% filter(rep == 'rep1') %>% select(-new) %>% unique()
r2 = df %>% filter(rep == 'rep2') %>% select(-new) %>% unique()
reps = merge(r1, r2, by = c('cohort','ferret_id','dpi')) %>% unique()
# these are the samples that only had one rep!
setdiff(levels(factor(r1$ferret_id)),
levels(factor(r2$ferret_id)))
[1] "1411" "1972" "2244"
setdiff(meta$ferretID, reps$ferret_id) # samples in meta not in seq data
[1] "1411" "1971" "1972" "2235" "2244" "2867" "2868"
setdiff(reps$ferret_id, meta$ferretID) # samples in seq data not in meta
character(0)
m = merge(reps, meta, by.x = c('ferret_id','cohort'), by.y = c("ferretID","cohort"), all = TRUE) %>%
filter(inf_route %in% c('Index','Contact','Control'))
write.csv(m, glue('{wkdir}/scripts/UPDATED.H9N2.metadata.csv'), row.names = FALSE)
# type check - only stock index direct
print(levels(factor(m$inf_route)))
[1] "Contact" "Control" "Index"
m$inf_route = factor(m$inf_route, levels = c('Control','Index','Contact'))
m = m %>% filter(name.x != is.na(name.x)) %>% unique()
p1 = m %>% filter(!(is.na(pair_numbers))) %>% unique() %>%
ggplot(., aes(x= dpi, y = pair_numbers, fill = diet)) +
geom_tile(color = 'black') +
PlotTheme3 +
DietcolScale_fill +
facet_grid(pair_diets~inf_route, scales = 'free', space = 'free')
print(p1)
ggsave(p1,
filename = glue("{wkdir}/DVG_figures/final.samples.pdf"),
width = 6,
height = 6, limitsize=FALSE, useDingbats = FALSE)
ggsave(p1,
filename = glue("{wkdir}/DVG_figures/final.samples.png"),
width = 6,
height = 6, limitsize=FALSE) #, useDingbats = FALSE)

dvg_reps = dvg_reps %>%
filter(DVG_freq.x > count_cut & DVG_freq.y > count_cut) %>%
unique() # make sure that both reps pass our cutoff
# add in variables for plotting
dvg_reps$ferret_day = paste0(dvg_reps$ferret_id, '_', dvg_reps$dpi)
m$ferret_day = paste0(m$ferret_id, '_', m$dpi)
stock_temp = dvg_reps %>% filter(dpi == 'stock') %>%
group_by(ferret_id, cohort, dpi, segment, name.x, name.y) %>%
add_tally(name = 'seg_deletion_richness') %>%
unique() %>%
ungroup() %>%
group_by(ferret_id, dpi, name.x, name.y, cohort) %>%
add_tally(name = 'deletion_richness') %>%
ungroup() %>%
unique()
s = stock_temp # will use later
# filter down stock temp information
stock_temp = stock_temp %>%
select(ferret_id, dpi, cohort,ferret_day, segment, deletion_richness, seg_deletion_richness) %>%
unique()
stock_temp = merge(stock_temp, m, by = c('ferret_id', 'dpi','cohort','ferret_day')) %>%
unique()
# filter out stock information, calculate dvg richness by segment and across genome for samples
dr = dvg_reps %>%
filter(dpi != 'stock') %>%
unique() %>%
group_by(ferret_id, dpi, segment, name.x, name.y, cohort) %>%
add_tally(name = 'seg_deletion_richness') %>%
ungroup() %>%
group_by(ferret_id, dpi, name.x, name.y, cohort) %>%
add_tally(name = 'deletion_richness') %>%
ungroup() %>%
unique()
# filter down information so you don't have duplicates
richness = dr %>%
select(ferret_id, dpi, cohort,ferret_day, segment, deletion_richness, seg_deletion_richness) %>%
unique()
# merge with metadata info
#richness = merge(richness, m, by = c('ferret_id', 'dpi','cohort','ferret_day'), all.y = TRUE) %>% # CHANGED
richness = merge(richness, m, by = c('ferret_id', 'dpi','cohort','ferret_day'), all.x = TRUE) %>%
unique() %>%
filter(!is.na(inf_route))
# make sure we filter out stock information (will add using the 's' dataframe generated above)
richness = richness %>% filter(dpi != 'stock')
reps_df = rbind(dr, s) %>% unique() # final reps richness df
reps_df = merge(reps_df, m, by = c('ferret_id','dpi','cohort','ferret_day')) %>% unique() # add metadata
p4 = reps_df %>%
select(segment, NewGap, EstimatedFragLength, diet) %>%
unique() %>%
ggplot(., aes(x= EstimatedFragLength)) +
geom_histogram(color = 'black') +
PlotTheme1 +
labs(x="estimated DVG frag. length (nt)", y='number of unique DVG species')
print(p4)
ggsave(p4,
filename = glue("{wkdir}/DVG_figures/deletion.size.pdf"),
width = 5,
height = 5, limitsize=FALSE, useDingbats = FALSE)
ggsave(p4,
filename = glue("{wkdir}/DVG_figures/deletion.size.png"),
width =5,
height = 5, limitsize=FALSE) #, useDingbats = FALSE)

p4_alt = reps_df %>%
select(segment, NewGap, EstimatedFragLength, diet, inf_route) %>%
unique() %>%
ggplot(., aes(x= EstimatedFragLength)) +
geom_histogram(color = 'black', binwidth = 50) +
facet_grid(inf_route~diet) +
PlotTheme1 +
labs(x="estimated DVG frag. length (nt)", y='number of unique DVG species')
print(p4_alt)
ggsave(p4_alt,
filename = glue("{wkdir}/DVG_figures/deletion.size.bydiet.bytype.pdf"),
width = 10,
height = 5, limitsize=FALSE, useDingbats = FALSE)

lean_index = reps_df %>% filter(inf_route == 'Index' & diet == 'Lean') %>%
unique() %>%
group_by(NewGap, segment, NewStart, NewEnd) %>%
add_tally(name = 'lean_deletion_count') %>%
ungroup() %>%
select(NewGap, segment, lean_deletion_count) %>%
unique()
obese_index = reps_df %>% filter(inf_route == 'Index' & diet == 'Obese') %>%
unique() %>%
group_by(NewGap, segment, NewStart, NewEnd) %>%
add_tally(name = 'obese_deletion_count') %>%
ungroup() %>%
select(NewGap, segment, obese_deletion_count) %>%
unique()
df = merge(lean_index, obese_index, by = c('NewGap','segment'), all = TRUE)
head(df)
df$lean_deletion_count[is.na(df$lean_deletion_count)] = 0
df$obese_deletion_count[is.na(df$obese_deletion_count)] = 0
p8 = reps_df %>% filter(inf_route == 'Index') %>%
unique() %>%
group_by(NewGap, segment, NewStart, NewEnd) %>%
add_tally(name = 'sample_count') %>%
ungroup() %>%
select(NewGap, segment,sample_count) %>%
unique() %>%
ggplot(., aes(x=sample_count, y = ..count../sum(..count..))) +
geom_histogram(color ='black') +
labs(x='number of samples with DVG type', y='proportion of DVGs in dataset (index only)') +
PlotTheme1
print(p8)
ggsave(p8,
filename = glue("{wkdir}/DVG_figures/sample.count.histo.pdf"),
width = 5,
height = 5, limitsize=FALSE, useDingbats = FALSE)
ggsave(p8,
filename = glue("{wkdir}/DVG_figures/sample.count.histo.png"),
width =5,
height = 5, limitsize=FALSE) #, useDingbats = FALSE)

reps_df$ave_dvg_freq = (reps_df$DVG_freq.x + reps_df$DVG_freq.y)/2
reps_df = reps_df %>%
arrange(ferret_day, ave_dvg_freq) %>%
group_by(ferret_day) %>%
mutate(order_number = row_number()) %>%
ungroup() %>%
unique()
reps_df %>%
group_by(NewGap, segment, inf_route, diet) %>%
mutate(mean_order = mean(order_number),
sample_count = n(),
min_order = min(order_number),
max_order = max(order_number),
median_ord = median(order_number)) %>%
ungroup() %>%
unique() %>%
select(segment, NewGap, mean_order, sample_count, min_order, max_order, median_ord, inf_route, diet) %>%
filter(sample_count > 1) %>%
unique() %>%
ggplot(., aes(y=mean_order, x = sample_count)) +
geom_point() +
PlotTheme1 +
facet_grid(.~diet + inf_route)

top_ten = reps_df %>% filter(order_number %in% c(1, 2,3 ,4, 5, 6, 7, 8, 9, 10)) %>% unique()
head(top_ten)
length(levels(factor(top_ten$NewGap)))
[1] 178
max(df$lean_deletion_count)
[1] 112
max(df$obese_deletion_count)
[1] 108
p9 = ggplot(df, aes(x=lean_deletion_count, y = obese_deletion_count)) +
geom_jitter(width = 0.1, height = 0.1, alpha = 0.3) +
geom_hline(yintercept = 0, linetype = 2, color = 'black') +
geom_hline(yintercept = 25, linetype = 2, color = 'red') +
geom_vline(xintercept = 0, linetype = 2, color = 'black') +
geom_vline(xintercept = 17, linetype = 2, color = 'red') +
labs(x= 'number of lean samples with DVG', y='number of obese samples with DVG') +
PlotTheme1
print(p9)
ggsave(p9,
filename = glue("{wkdir}/DVG_figures/sample.count.lean.v.obese.pdf"),
width = 5,
height = 5, limitsize=FALSE, useDingbats = FALSE)
ggsave(p9,
filename = glue("{wkdir}/DVG_figures/sample.count.lean.v.obese.png"),
width =5,
height = 5, limitsize=FALSE) #, useDingbats = FALSE)

richness = rbind(richness, stock_temp)
#richness$deletion_richness[is.na(richness$deletion_richness)] = 0
DAYS = c('stock','d02','d04','d06','d08','d10','d12')
richness$dpi = factor(richness$dpi, levels = DAYS)
richness %>% filter(dpi %in% c('d02','d04')) %>%
filter(inf_route == 'Index' | inf_route == 'Control') %>%
filter(!(is.na(inf_route))) %>%
select(ferret_id, dpi, deletion_richness, inf_route, diet, pair_diets, cohort) %>%
unique() %>%
group_by(ferret_id) %>%
add_tally(name = 'n') %>%
ungroup() %>%
filter(n >= 2) %>%
ungroup() %>%
unique() %>%
ggplot(., aes(x=dpi, y = deletion_richness, color = cohort, group=ferret_id, shape = diet)) +
#geom_boxplot() +
geom_line() +
geom_point(size = 2) +
PlotTheme1 +
scale_color_brewer(palette = 'Set1')

#DietcolScale +
#facet_grid(.~cohort)
p7 = richness %>% filter(dpi %in% c('d02','d04','d06')) %>%
filter(inf_route == 'Index' | inf_route == 'Control') %>%
select(ferret_id, dpi, deletion_richness, inf_route, diet, pair_diets, cohort) %>%
unique() %>%
group_by(ferret_id) %>%
add_tally(name = 'n') %>%
ungroup() %>%
filter(n >= 2) %>%
ungroup() %>%
unique() %>%
ggplot(., aes(x=dpi, y = deletion_richness, color = diet, group=ferret_id, shape = diet)) +
#geom_boxplot() +
geom_line() +
geom_point(size = 2) +
PlotTheme1 +
DietcolScale
#facet_grid(.~cohort)
print(p7)
ggsave(p7,
filename = glue("{wkdir}/DVG_figures/richness.index.pdf"),
width = 5,
height = 5, limitsize=FALSE, useDingbats = FALSE)
ggsave(p7,
filename = glue("{wkdir}/DVG_figures/richness.index.png"),
width =5,
height = 5, limitsize=FALSE) #, useDingbats = FALSE)

colnames(richness)
[1] "ferret_id" "dpi" "cohort" "ferret_day" "segment"
[6] "deletion_richness" "seg_deletion_richness" "name.x" "rep.x" "name.y"
[11] "rep.y" "DPI" "sample" "inf_route" "diet"
[16] "titer" "log10_titer" "HAI_21dpi" "Ct_Mgene" "resequenced"
[21] "pair_numbers" "pair_diets"
order_typeday = c('Control_stock',
'Index_d02','Index_d04','Index_d06','Index_d08','Index_d10','Index_d12',
'Contact_d02','Contact_d04','Contact_d06','Contact_d08','Contact_d10','Contact_d12')
richness$type_day = paste0(richness$inf_route, '_', richness$dpi)
richness$type_day = factor(richness$type_day, levels = order_typeday)
p2 = richness %>% filter(diet == 'Obese' & pair_diets == 'OB>OB') %>%
select(ferret_id, dpi, deletion_richness, inf_route, diet, pair_numbers, pair_diets, type_day) %>%
ungroup() %>%
unique() %>%
ggplot(., aes(x=type_day, y = deletion_richness, color = pair_numbers, group=pair_numbers)) +
#geom_boxplot() +
geom_line(size = 1) +
geom_point(size = 2) +
labs(x='dpi (by index case)', y='DVG richness') +
PlotTheme1 +
scale_color_brewer(palette = 'Set2') #+
#DietcolScale +
#facet_grid(.~inf_route)
print(p2)
ggsave(p2,
filename = glue("{wkdir}/DVG_figures/obese.to.obese.diversity.pdf"),
width = 8,
height = 6, limitsize=FALSE, useDingbats = FALSE)
ggsave(p2,
filename = glue("{wkdir}/DVG_figures/obese.to.obese.diversity.png"),
width =8,
height = 6, limitsize=FALSE) #, useDingbats = FALSE)

gen_rich = richness %>%
select(ferret_id, dpi, cohort,deletion_richness, inf_route, diet, pair_numbers, pair_diets, type_day) %>%
unique()
head(gen_rich)
gen_rich %>% filter(dpi %in% c('d02','d04','d06','stock')) %>%
filter(inf_route == 'Index' | inf_route == "Control") %>%
ggplot(., aes(x=diet, y = deletion_richness, group = diet)) +
geom_boxplot(outlier.shape = NA) +
geom_jitter(width = 0.2, aes(color = diet)) +
labs(x='segment',y='deletion richness') +
PlotTheme1 +
DietcolScale +
facet_grid(.~dpi)

Test for significance
o = filter(gen_rich, inf_route == "Index" & dpi == "d06" & diet == "Obese")
l = filter(gen_rich, inf_route == "Index" & dpi == "d06" & diet == "Lean")
t.test(o$deletion_richness,l$deletion_richness)
Welch Two Sample t-test
data: o$deletion_richness and l$deletion_richness
t = 0.66564, df = 5.7765, p-value = 0.5313
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-39.95197 69.42816
sample estimates:
mean of x mean of y
68.57143 53.83333
seg_rich %>% filter(ferret_id == 1787) %>% head()
richness %>% filter(ferret_id == 1787) %>% head()
temp %>% filter(ferret_id == 1787)
NA
p3 = seg_rich %>% filter(segment %in% SEGMENTS) %>%
ggplot(., aes(x=segment, y = seg_deletion_richness)) +
geom_boxplot() +
labs(x='segment',y='deletion richness') +
PlotTheme1
print(p3)
ggsave(p3,
filename = glue("{wkdir}/DVG_figures/segment.richness.pdf"),
width = 5,
height = 5, limitsize=FALSE, useDingbats = FALSE)
ggsave(p3,
filename = glue("{wkdir}/DVG_figures/segment.richness.png"),
width =5,
height = 5, limitsize=FALSE) #, useDingbats = FALSE)

seg_rich$seg_weight = paste0(seg_rich$segment, '_', seg_rich$diet)
seg_rich$diet = factor(seg_rich$diet, levels = c('Control','Lean','Obese'))
seg_rich %>% filter(segment %in% SEGMENTS) %>%
drop_na(inf_route) %>%
ggplot(., aes(x=segment, y = seg_deletion_richness, group = seg_weight, color = diet)) +
geom_boxplot() +
labs(x='segment',y='deletion richness') +
PlotTheme1 +
weight_colScale +
facet_grid(.~inf_route)

p6 = seg_rich %>% filter(segment %in% SEGMENTS & dpi %in% c('d02','d04','d06','stock')) %>%
filter(inf_route == 'Index' | inf_route == "Control") %>%
ggplot(., aes(x=segment, y = seg_deletion_richness, group = seg_weight, color = diet)) +
geom_boxplot(outlier.shape = NA) +
labs(x='segment',y='deletion richness') +
PlotTheme1 +
DietcolScale +
facet_grid(.~dpi)
print(p6)
ggsave(p6,
filename = glue("{wkdir}/DVG_figures/segment.index.richness.pdf"),
width = 8,
height = 4, limitsize=FALSE, useDingbats = FALSE)
ggsave(p6,
filename = glue("{wkdir}/DVG_figures/segment.index.richness.png"),
width =8,
height = 4, limitsize=FALSE) #, useDingbats = FALSE)

NA
NA
# 1973, 1977, and 1986 are listed as obese when they are actually lean, and 1984 is listed as lean when it is actually obese
seg_rich %>%
#filter(!inf_route %in% c('stock','lean','obese')) %>%
drop_na(inf_route) %>%
filter(ferret_id == 1408)
old_obese = filter(seg_rich, ferret_id %in% c(1973, 1977, 1986)) %>% unique()
old_obese$diet = "Obese"
old_lean = filter(seg_rich,ferret_id == 1984) %>% unique()
old_lean$diet = "Lean"
old_same = filter(seg_rich, ferret_id != c(1973, 1977, 1986, 1984))
deleteit = rbind(old_obese,old_lean,old_same)
deleteit %>% filter(!ferret_id %in% c(1973, 1977,1986, 1984) &
segment %in% SEGMENTS & dpi %in% c('d02','d04','d06','stock')) %>%
drop_na(inf_route) %>%
filter(inf_route == 'Index' | inf_route == "Control") %>%
ggplot(., aes(x=segment, y = seg_deletion_richness, group = seg_weight, color = diet)) +
geom_boxplot(outlier.shape = NA) +
labs(x='segment',y='deletion richness') +
PlotTheme1 +
DietcolScale +
facet_grid(.~dpi)

#seg_rich %>% filter(ferret_id %in% c(1973, 1977,1986, 1984) & dpi == 'd06') %>%
# select(ferret_id, segment, dpi, seg_deletion_richness)
Test for significance
o = filter(seg_rich, inf_route == "Index" & dpi == "d06" & segment == "H9N2_PB2" & diet == "Obese")
l = filter(seg_rich, inf_route == "Index" & dpi == "d06" & segment == "H9N2_PB2" & diet == "Lean")
t.test(o$seg_deletion_richness,l$seg_deletion_richness)
Welch Two Sample t-test
data: o$seg_deletion_richness and l$seg_deletion_richness
t = 0.71692, df = 6.242, p-value = 0.4994
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-8.051023 14.812928
sample estimates:
mean of x mean of y
15.71429 12.33333
seg_rich %>% filter(inf_route == 'Index' & segment %in% SEGMENTS) %>%
ungroup() %>%
unique() %>%
ggplot(., aes(x=type_day, y = seg_deletion_richness, color = segment, group=segment)) +
#geom_boxplot() +
geom_line(size = 1) +
geom_point(size = 2) +
labs(x='dpi (by index case)', y='DVG richness') +
PlotTheme1 +
scale_color_brewer(palette = 'Set2') +
#weight_colScale +
facet_grid(.~diet + ferret_id, scales = 'free', space = 'free')

p4 = seg_rich %>% filter(diet == 'Obese' & pair_diets == 'OB>OB' & segment %in% SEGMENTS) %>%
ungroup() %>%
unique() %>%
ggplot(., aes(x=type_day, y = seg_deletion_richness, color = segment, group=segment)) +
#geom_boxplot() +
geom_line(size = 1) +
geom_point(size = 2) +
labs(x='dpi (by index case)', y='DVG richness') +
PlotTheme1 +
scale_color_brewer(palette = 'Set2') +
#weight_colScale +
facet_grid(.~pair_numbers, scales = 'free', space = 'free')
print(p4)
ggsave(p4,
filename = glue("{wkdir}/DVG_figures/segment.obese.to.obese.richness.pdf"),
width = 12,
height = 4, limitsize=FALSE, useDingbats = FALSE)
ggsave(p4,
filename = glue("{wkdir}/DVG_figures/segment.obese.to.obese.richness.png"),
width =12,
height = 4, limitsize=FALSE) #, useDingbats = FALSE)

End of Kate’s code
Which DVGs are shared between stock and index?
reps_df$DVG = paste0(reps_df$segment,"_",reps_df$DVG_group)
F17_stock = filter(reps_df ,inf_route == "Control", cohort == "F17")
F17_stock_dvg = unique(F17_stock$DVG)
W17_stock = filter(reps_df ,inf_route == "Control", cohort == "W17")
W17_stock_dvg = unique(W17_stock$DVG)
Sm18_stock = filter(reps_df ,inf_route == "Control", cohort == "Sm18")
Sm18_stock_dvg = unique(Sm18_stock$DVG)
Sp19_stock = filter(reps_df ,inf_route == "Control", cohort == "Sp19")
Sp19_stock_dvg = unique(Sp19_stock$DVG)
Sp20_stock = filter(reps_df ,inf_route == "Control", cohort == "Sp20")
Sp20_stock_dvg = unique(Sp20_stock$DVG)
F17_index = filter(reps_df ,inf_route == "Index", cohort == "F17")
F17_index_dvg = unique(F17_index$DVG)
W17_index = filter(reps_df ,inf_route == "Index", cohort == "W17")
W17_index_dvg = unique(W17_index$DVG)
Sm18_index = filter(reps_df ,inf_route == "Index", cohort == "Sm18")
Sm18_index_dvg = unique(Sm18_index$DVG)
Sp19_index = filter(reps_df ,inf_route == "Index", cohort == "Sp19")
Sp19_index_dvg = unique(Sp19_index$DVG)
Sp20_index = filter(reps_df ,inf_route == "Index", cohort == "Sp20")
Sp20_index_dvg = unique(Sp20_index$DVG)
F17_shared = F17_index %>% filter(DVG %in% F17_stock_dvg) %>% filter((DVG %in% F17_index_dvg)) %>% unique()
F17_denovo = F17_index %>% filter((DVG %in% F17_index_dvg)) %>% filter(!(DVG %in% F17_stock_dvg)) %>% unique()
W17_shared = W17_index %>% filter(DVG %in% W17_stock_dvg) %>% filter((DVG %in% W17_index_dvg)) %>% unique()
W17_denovo = W17_index %>% filter((DVG %in% W17_index_dvg)) %>% filter(!(DVG %in% W17_stock_dvg)) %>% unique()
Sm18_shared = Sm18_index %>% filter(DVG %in% Sm18_stock_dvg) %>% filter((DVG %in% Sm18_index_dvg)) %>% unique()
Sm18_denovo = Sm18_index %>% filter((DVG %in% Sm18_index_dvg)) %>% filter(!(DVG %in% Sm18_stock_dvg)) %>% unique()
Sp19_shared = Sp19_index %>% filter(DVG %in% Sp19_stock_dvg) %>% filter((DVG %in% Sp19_index_dvg)) %>% unique()
Sp19_denovo = Sp19_index %>% filter((DVG %in% Sp19_index_dvg)) %>% filter(!(DVG %in% Sp19_stock_dvg)) %>% unique()
Sp20_shared = Sp20_index %>% filter(DVG %in% Sp20_stock_dvg) %>% filter((DVG %in% Sp20_index_dvg)) %>% unique() # still not working
Sp20_denovo = Sp20_index %>% filter((DVG %in% Sp20_index_dvg)) %>% filter(!(DVG %in% Sp20_stock_dvg)) %>% unique() # still not working
stock_shared = rbind(F17_shared,W17_shared,Sm18_shared,Sp19_shared,Sp20_shared)
index_unique = rbind(F17_denovo,W17_denovo,Sm18_denovo,Sp19_denovo,Sp20_denovo)
stock_obese = filter(stock_shared, diet == "Obese")
o_dvg = unique(stock_obese$DVG)
stock_lean = filter(stock_shared, diet == "Lean")
l_dvg = unique(stock_lean$DVG)
stock_dvg <- list(Obese = o_dvg, Lean = l_dvg)
StockDVGs = ggVennDiagram(stock_dvg)
print(StockDVGs)
ggsave(StockDVGs, file = "StockDVGs.pdf", path = saveitdir)
Saving 7.29 x 4.51 in image

ShockSharedDVGs = ggplot(stock_shared, aes(x = dpi, y = DVG)) +
geom_point() +
geom_line(aes(group = DVG)) +
facet_grid(~segment) +
PlotTheme1
print(ShockSharedDVGs)
ggsave(ShockSharedDVGs, file = "ShockSharedDVGs.pdf", path = saveitdir)
Saving 7.29 x 4.51 in image

Are there diet-specific DVGs in index ferrets?
index_obese = filter(index_unique, diet == "Obese")
o_dvg = unique(index_obese$DVG)
index_lean = filter(index_unique, diet == "Lean")
l_dvg = unique(index_lean$DVG)
diet_dvg <- list(Obese = o_dvg, Lean = l_dvg)
DietUniqueDVGs = ggVennDiagram(diet_dvg)
print(DietUniqueDVGs)
ggsave(DietUniqueDVGs, file = "DietUniqueDVGs.pdf", path = saveitdir)
Saving 7.29 x 4.51 in image

Pulling out diet-specific DVGs
lean = index_lean %>%
filter(DVG %in% l_dvg) %>%
filter(!(DVG %in% o_dvg)) %>%
unique()
lean = lean %>%
group_by(DVG) %>%
mutate(count = 1, totalsamp = sum(count))
mult_lean = filter(lean, totalsamp > 1) %>%
unique()
obese = index_unique %>%
filter((DVG %in% o_dvg)) %>%
filter(!(DVG %in% l_dvg)) %>%
unique()
obese = obese %>%
group_by(DVG) %>%
mutate(count = 1, totalsamp = sum(count))
mult_obese = filter(obese, totalsamp > 1) %>%
unique()
lean_uniques = lean %>%
ungroup() %>%
select(segment,DVG_group,GroupBoundaries,totalsamp) %>%
unique() %>%
arrange(desc(totalsamp))
obese_uniques = obese %>%
ungroup() %>%
select(segment,DVG_group,GroupBoundaries,totalsamp) %>%
unique() %>%
arrange(desc(totalsamp))
lean_DVG_sizes = lean %>% ungroup %>% select(DVG,DVG_group, DeletionSize, NewStart, NewEnd, diet) %>%
unique() %>%
arrange(desc(DeletionSize)) %>%
mutate(name = factor(DVG, levels = unique(DVG)))
ggplot(lean_DVG_sizes, aes(x = DeletionSize, y = name)) +
geom_col() +
#facet_grid(segment~strain) +
PlotTheme1

#ggsave("test_dvg.pdf", a, path = saveitdir, height = 30, width = 5)
lean_DVG_sizes_plot = ggplot(lean_DVG_sizes, aes(x = NewStart, xend = NewEnd, y = name, yend = name, color = diet)) +
geom_segment() +
#facet_grid(segment~strain) +
PlotTheme1 +
DietcolScale
print(lean_DVG_sizes_plot)
ggsave("lean_DVG_sizes_plot.pdf",lean_DVG_sizes_plot, path = saveitdir, height = 10, width = 10)

lean_DVG_size_seg = lean %>% ungroup %>% select(DVG,DVG_group, DeletionSize, NewStart, NewEnd, segment,diet) %>%
unique() %>%
arrange(desc(segment),desc(DeletionSize)) %>%
mutate(name = factor(DVG, levels = unique(DVG)))
lean_DVG_size_seg_plot = ggplot(lean_DVG_size_seg, aes(x = NewStart, xend = NewEnd, y = name, yend = name, color = diet)) +
geom_segment() +
facet_grid(~segment) +
PlotTheme1 +
DietcolScale
print(lean_DVG_size_seg_plot)
ggsave("lean_DVG_size_seg_plot.pdf",lean_DVG_size_seg_plot,path = saveitdir, height = 10, width = 10)

obese_DVG_sizes = obese %>% ungroup %>% select(DVG,DVG_group, DeletionSize, NewStart, NewEnd, diet) %>%
unique() %>%
arrange(desc(DeletionSize)) %>%
mutate(name = factor(DVG, levels = unique(DVG)))
ggplot(obese_DVG_sizes, aes(x = DeletionSize, y = name)) +
geom_col() +
#facet_grid(segment~strain) +
PlotTheme1

#ggsave("test_dvg.pdf", a, path = saveitdir, height = 30, width = 5)
obese_DVG_sizes_plot = ggplot(obese_DVG_sizes, aes(x = NewStart, xend = NewEnd, y = name, yend = name, color = diet)) +
geom_segment() +
#facet_grid(segment~strain) +
PlotTheme1 +
DietcolScale
print(obese_DVG_sizes_plot)
ggsave("obese_DVG_sizes_plot.pdf",obese_DVG_sizes_plot, path = saveitdir, height = 10, width = 10)

obese_DVG_size_seg = obese %>% ungroup %>% select(DVG,DVG_group, DeletionSize, NewStart, NewEnd, segment,diet) %>%
unique() %>%
arrange(desc(segment),desc(DeletionSize)) %>%
mutate(name = factor(DVG, levels = unique(DVG)))
obese_DVG_size_seg_plot = ggplot(obese_DVG_size_seg, aes(x = NewStart, xend = NewEnd, y = name, yend = name, color = diet)) +
geom_segment() +
facet_grid(~segment) +
PlotTheme1 +
DietcolScale
print(obese_DVG_size_seg_plot)
ggsave("obese_DVG_size_seg_plot.pdf",obese_DVG_size_seg_plot, path = saveitdir, height = 10, width = 10)

Are DVGs transmitted?
print(i)
[1] "1794_d04"
contact_dvgs = filter(dvg_df, inf_route == "Index") %>% count(ferret_id,dpi,diet) %>%
ggplot(., aes(x = dpi, y = n, color = diet)) +
geom_point() +
geom_line(aes(group = ferret_id)) +
facet_grid(~ferret_id) +
ylab("DVG richness") +
xlab("DPI") +
PlotTheme1 +
DietcolScale
print(contact_dvgs)
ggsave(contact_dvgs, file = "contact_dvgs.pdf", path = saveitdir)
Saving 7.29 x 4.51 in image

LS0tCnRpdGxlOiAiRFZHX0FuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpLYXRlJ3MgRFZHIGNvZGUKCmBgYHtyfQptZXNzYWdlKCJMb2FkaW5nIHBhY2thZ2VzIikKbGlicmFyeSgnZ2dwbG90MicpCmxpYnJhcnkoJ3JlYWRyJykKbGlicmFyeSgncmVzaGFwZTInKQpsaWJyYXJ5KCdnZ3B1YnInKQpsaWJyYXJ5KCdwbHlyJykKbGlicmFyeSgndGlkeXZlcnNlJykKbGlicmFyeSgnZHBseXInKQpsaWJyYXJ5KCdnbHVlJykKbGlicmFyeSgnZ2dWZW5uRGlhZ3JhbScpCmBgYAoKYGBge3J9CiMgcGFyYW10ZXJzIHVzZWQgd2hlbiBydW5uaW5nIGRpdnJnZQpncm91cGluZ19wYXJhbSA9IDUKbWF0Y2hfbGVuZ3RoX3BhcmFtID0gMjgKcmVhZExlbmd0aCA9IDE1MAoKIyBkZWxldGlvbiByZWFkIGNvdW50IGN1dG9mZnMKY291bnRfY3V0ID0gMzAKYGBgCgpgYGB7cn0KbWVzc2FnZSgiU2V0dGluZyB3b3JrIGRpcmVjdG9yeSBhbmQgaW5wdXQgZmlsZSBuYW1lcyIpCndrZGlyID0gIi9Vc2Vycy9tYXJpc3Nha25vbGwvRGVza3RvcC9HaXRIdWIvT2Jlc2l0eS9OZXdFeHRyYWN0aW9ucy9IOU4yL0RWR3MiCnNldHdkKHdrZGlyKQpgYGAKCmBgYHtyfQppZiAoIWRpci5leGlzdHMoZ2x1ZSgie3drZGlyfS9EVkdfZmlndXJlcyIpKSkgewogICAgICAgIGRpci5jcmVhdGUoZ2x1ZSgie3drZGlyfS9EVkdfZmlndXJlcyIpKQogICAgICB9CgpzYXZlaXRkaXIgPSBnbHVlKCJ7d2tkaXJ9L0RWR19maWd1cmVzIikKYGBgCgpgYGB7cn0Kc291cmNlKGdsdWUoJ3t3a2Rpcn0vc2NyaXB0cy9vYmVzZV9QbG90UHJlcC5SJykpCmBgYAoKYGBge3J9CiMgbG9hZGluZyBpbiBtZXRhZGF0YSBhbmQgY292ZXJhZ2UgZGF0YQptZXRhZmlsZSA9IGdsdWUoInt3a2Rpcn0vLi4vSDlfTWV0YWRhdGEuY3N2IikKbWV0YSA9IHJlYWQuY3N2KGZpbGU9bWV0YWZpbGUsaGVhZGVyPVQsc2VwPSIsIixuYS5zdHJpbmdzID0gYygnJykpIAptZXRhID0gZmlsdGVyKG1ldGEsIHJlc2VxdWVuY2VkID09ICJ5ZXMiKSAlPiUgZmlsdGVyKGNvaG9ydCAhPSAiTkQiKQoKdHJhbnNtaXNzaW9uX2luZm8gPSAiL1VzZXJzL21hcmlzc2Frbm9sbC9EZXNrdG9wL0dpdEh1Yi9PYmVzaXR5L05ld0V4dHJhY3Rpb25zL0g5TjIvVHJhbnNtaXNzaW9uUGFpcnMuY3N2IgpwYWlycyA9IHJlYWQuY3N2KHRyYW5zbWlzc2lvbl9pbmZvLCBoZWFkZXIgPSBUKQoKbWV0YSA9IG1lcmdlKG1ldGEsIHBhaXJzLCBhbGwueCA9IFRSVUUpICU+JSB1bmlxdWUoKQoKY292ZXJhZ2VfcGFzc2ZpbGUgPSBnbHVlKCd7d2tkaXJ9L3NjcmlwdHMvSDlOMi5jb3ZlcmFnZS5wYXNzLmNoZWNrLjIwMC4wLjk1LmNzdicpCmNvdl9jaGVjayA9IHJlYWQuY3N2KGZpbGU9Y292ZXJhZ2VfcGFzc2ZpbGUsaGVhZGVyPVQsc2VwPSIsIixuYS5zdHJpbmdzID0gYygnJykpCmBgYAoKYGBge3J9CiMgZmlsdGVyIGZvciBzYW1wbGVzIHRoYXQgZWl0aGVyIHBhc3Mgd2l0aCBhIHllcyBPUiBoYXMgZ29vZCBhdmVyYWdlIGNvdmVyYWdlIGFuZCBwZXJjZW50YWdlIGNvdiBhdCAyMDB4IGlzID4gODAKY292X2ZpbHRfbmFtZXMgPSBjb3ZfY2hlY2sgJT4lIGZpbHRlcihwYXNzID09ICdZRVMnIHwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbl9jb3ZlcmFnZSA+PSAyMDAgIHwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVyY2VudGFnZSA+IDAuNCkgJT4lIAogICAgICAgICAgICBzZWxlY3QobmFtZSwgc2VnbWVudCkgJT4lIAogICAgICAgICAgICB1bmlxdWUoKQoKIyBjaGVjayBzZWdtZW50IGNvdW50CmNvdl9maWx0X25hbWVzID0gY292X2ZpbHRfbmFtZXMgJT4lIGdyb3VwX2J5KG5hbWUpICU+JSBhZGRfdGFsbHkobmFtZSA9ICdzZWdtZW50X3RhbGx5JykgJT4lIAogICAgICAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHNlZ21lbnRfdGFsbHkgPT0gOCkgJT4lIAogICAgICAgICAgICAgICAgICAgIHVuaXF1ZSgpIAoKcHVsbF9uYW1lcyA9IGMobGV2ZWxzKGZhY3Rvcihjb3ZfZmlsdF9uYW1lcyRuYW1lKSkpICAjIGxpc3QgdG8gcHVsbCBuYW1lcyBmcm9tCmBgYAoKYGBge3J9CmR2Z2ZpbGUgPSBnbHVlKCd7d2tkaXJ9L0g5TjIuRFZHLkZJTkFMLk9uZUdhcC5ONS5NaXMyLk0yOC5HNS5jc3YnKSAjIGR2ZyBmaWxlCmR2ZyA9IHJlYWQuY3N2KGZpbGU9ZHZnZmlsZSxoZWFkZXI9VCxzZXA9IiwiLG5hLnN0cmluZ3MgPSBjKCcnKSkKCmR2ZyA9IGR2ZyAlPiUgZmlsdGVyKG5hbWUgJWluJSBwdWxsX25hbWVzKSAjIGZpbHRlciBmb3Igc2FtcGxlcyB0aGF0IHBhc3Mgb3VyIGNvdmVyYWdlIGNoZWNrcwpkdmckc2FtcGxlID0gZHZnJG5hbWUgICMgZ2VuZXJhdGUgbmV3IGNvbHVtbiBzbyB3ZSBjYW4gc2VwYXJhdGUKZHZnID0gZHZnICU+JSBzZXBhcmF0ZShzYW1wbGUsIGMoJ25ldycsJ2NvaG9ydCcsJ2ZlcnJldF9pZCcsJ2RwaScsJ3JlcCcpLCAnXycpICAjIHNlcGFyYXRlIGludG8gaW5mbwoKQ09OVFJPTFMgPSBkdmcgJT4lIGZpbHRlcihmZXJyZXRfaWQgPT0gJ0hLMTA3MycpICAjIHB1bGxpbmcgb3V0IGNvbnRyb2xzCkNPTlRST0xTJHJlcCA9IENPTlRST0xTJGRwaQpDT05UUk9MUyRkcGkgPSAnc3RvY2snICAjIGFkZGluZyBpbiBzdG9jayBpbmZvCgpkdmcgPSBkdmcgJT4lIGZpbHRlcighbmFtZSAlaW4lIGMobGV2ZWxzKGZhY3RvcihDT05UUk9MUyRuYW1lKSkpKSAlPiUgdW5pcXVlKCkKCmR2ZyA9IHJiaW5kKGR2ZywgQ09OVFJPTFMpICMgcmJpbmQgZXZlcnl0aGluZyBzbyBpdCBpcyBhbGwgaW4gb25lIGRhdGFmcmFtZQpgYGAKCmBgYHtyfQojIHByZXBwaW5nIHJlcCBpbmZvcm1hdGlvbgpkdmcgPSBkdmcgJT4lIHNlbGVjdCgtU2VnVG90YWxEVkcsIC1uZXcpICU+JSBmaWx0ZXIoRFZHX2ZyZXEgPj0gY291bnRfY3V0KSAlPiUgdW5pcXVlKCkgICMgZmlsdGVyIGZvciB0aG9zZSB0aGF0IHBhc3MgY3V0b2ZmcwpyZXAxID0gZHZnICU+JSBmaWx0ZXIocmVwID09ICdyZXAxJykgJT4lIHVuaXF1ZSgpCnJlcDIgPSBkdmcgJT4lIGZpbHRlcihyZXAgPT0gJ3JlcDInKSAlPiUgdW5pcXVlKCkKYGBgCgpgYGB7cn0KIyBtZXJnZSByZXBzIGludG8gb25lCmR2Z19yZXBzID0gbWVyZ2UocmVwMSwgcmVwMiwgYnkgPSBjKCdjb2hvcnQnLCdmZXJyZXRfaWQnLCdkcGknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdzZWdtZW50Jywnc2VnbWVudF9zaXplJywnc3RyYWluJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRFZHX2dyb3VwJywnTmV3R2FwJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTmV3U3RhcnQnLCdOZXdFbmQnLCdHcm91cEJvdW5kYXJpZXMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdEZWxldGlvblNpemUnLCdFc3RpbWF0ZWRGcmFnTGVuZ3RoJyksIGFsbCA9IFRSVUUpICU+JSB1bmlxdWUoKQpgYGAKCmBgYHtyfQojIGFkZCBpbiB6ZXJvcwpkdmdfcmVwcyREVkdfZnJlcS54W2lzLm5hKGR2Z19yZXBzJERWR19mcmVxLngpXSA9IDAKZHZnX3JlcHMkRFZHX2ZyZXEueVtpcy5uYShkdmdfcmVwcyREVkdfZnJlcS55KV0gPSAwCmBgYAoKYGBge3J9CmdncGxvdChkdmdfcmVwcywgYWVzKHg9RFZHX2ZyZXEueCwgeT1EVkdfZnJlcS55KSkgKyAKICAgIGdlb21fcG9pbnQoKSArIAogICAgUGxvdFRoZW1lMQpgYGAKCmBgYHtyfQojIG51bWJlciBvZiBzYW1wbGVzPwpsZXZlbHMoZmFjdG9yKGR2Z19yZXBzJGZlcnJldF9pZCkpICU+JSBsZW5ndGgoKQpgYGAKCmBgYHtyfQojIHJlb3JkZXIgYnkgc2VnbWVudCBzaXplClNFR01FTlRTID0gYygnSDlOMl9QQjInLCAnSDlOMl9QQjEnLAogICAgICAgICAgICAnSDlOMl9QQScsJ0g5TjJfSEEnLCdIOU4yX05QJywgCiAgICAgICAgICAgICdIOU4yX05BJywnSDlOMl9NUCcsJ0g5TjJfTlMnKQoKY292X2NoZWNrJHNlZ21lbnQgPSBmYWN0b3IoY292X2NoZWNrJHNlZ21lbnQsIGxldmVscyA9IFNFR01FTlRTKQpgYGAKCmBgYHtyfQpjb3ZfY2hlY2sgJT4lIAogICAgZmlsdGVyKG5hbWUgJWluJSBwdWxsX25hbWVzKSAlPiUKICAgIGdncGxvdCguLCBhZXMoeD0gc2VnbWVudCwgeSA9IG1lYW5fY292ZXJhZ2UpKSArIAogICAgZ2VvbV9ib3hwbG90KCkgKyAKICAgIFBsb3RUaGVtZTEKCmNvdl9jaGVjayAlPiUgCiAgICBmaWx0ZXIobmFtZSAlaW4lIHB1bGxfbmFtZXMpICU+JQogICAgZ2dwbG90KC4sIGFlcyh4PSBzZWdtZW50LCB5ID0gbWVkaWFuX2NvdmVyYWdlKSkgKyAKICAgIGdlb21fYm94cGxvdCgpICsgCiAgICBQbG90VGhlbWUxCgpjb3ZfY2hlY2sgJT4lIAogICAgZmlsdGVyKG5hbWUgJWluJSBwdWxsX25hbWVzKSAlPiUKICAgIGdncGxvdCguLCBhZXMoeD0gc2VnbWVudCwgeSA9IHBlcmNlbnRhZ2UpKSArIAogICAgZ2VvbV9ib3hwbG90KCkgKyAKICAgIFBsb3RUaGVtZTEKYGBgCgpgYGB7cn0KZGYgPSBjb3ZfZmlsdF9uYW1lcyAlPiUgc2VsZWN0KC1zZWdtZW50LCAtc2VnbWVudF90YWxseSkgJT4lIHVuaXF1ZSgpCmRmJHNhbXBsZSA9IGRmJG5hbWUKZGYgPSBkZiAlPiUgc2VwYXJhdGUoc2FtcGxlLCBjKCduZXcnLCdjb2hvcnQnLCdmZXJyZXRfaWQnLCdkcGknLCdyZXAnKSwgJ18nKQoKQ09OVFJPTFMgPSBkZiAlPiUgZmlsdGVyKGZlcnJldF9pZCA9PSAnSEsxMDczJykKQ09OVFJPTFMkcmVwID0gQ09OVFJPTFMkZHBpCkNPTlRST0xTJGRwaSA9ICdzdG9jaycKCmRmID0gZGYgJT4lIGZpbHRlcighbmFtZSAlaW4lIGMobGV2ZWxzKGZhY3RvcihDT05UUk9MUyRuYW1lKSkpKSAlPiUgdW5pcXVlKCkKZGYgPSByYmluZChkZiwgQ09OVFJPTFMpCgpyMSA9IGRmICU+JSBmaWx0ZXIocmVwID09ICdyZXAxJykgJT4lIHNlbGVjdCgtbmV3KSAlPiUgdW5pcXVlKCkKcjIgPSBkZiAlPiUgZmlsdGVyKHJlcCA9PSAncmVwMicpICU+JSBzZWxlY3QoLW5ldykgJT4lIHVuaXF1ZSgpCnJlcHMgPSBtZXJnZShyMSwgcjIsIGJ5ID0gYygnY29ob3J0JywnZmVycmV0X2lkJywnZHBpJykpICU+JSB1bmlxdWUoKQoKIyB0aGVzZSBhcmUgdGhlIHNhbXBsZXMgdGhhdCBvbmx5IGhhZCBvbmUgcmVwIQpzZXRkaWZmKGxldmVscyhmYWN0b3IocjEkZmVycmV0X2lkKSksCiAgICAgICBsZXZlbHMoZmFjdG9yKHIyJGZlcnJldF9pZCkpKQpgYGAKCmBgYHtyfQpzZXRkaWZmKG1ldGEkZmVycmV0SUQsIHJlcHMkZmVycmV0X2lkKSAgIyBzYW1wbGVzIGluIG1ldGEgbm90IGluIHNlcSBkYXRhCnNldGRpZmYocmVwcyRmZXJyZXRfaWQsIG1ldGEkZmVycmV0SUQpICMgc2FtcGxlcyBpbiBzZXEgZGF0YSBub3QgaW4gbWV0YQoKbSA9IG1lcmdlKHJlcHMsIG1ldGEsIGJ5LnggPSBjKCdmZXJyZXRfaWQnLCdjb2hvcnQnKSwgYnkueSA9IGMoImZlcnJldElEIiwiY29ob3J0IiksIGFsbCA9IFRSVUUpICU+JSAKICBmaWx0ZXIoaW5mX3JvdXRlICVpbiUgYygnSW5kZXgnLCdDb250YWN0JywnQ29udHJvbCcpKQogICAgICAgICAKd3JpdGUuY3N2KG0sIGdsdWUoJ3t3a2Rpcn0vc2NyaXB0cy9VUERBVEVELkg5TjIubWV0YWRhdGEuY3N2JyksIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCmBgYHtyfQojIHR5cGUgY2hlY2sgLSBvbmx5IHN0b2NrIGluZGV4IGRpcmVjdApwcmludChsZXZlbHMoZmFjdG9yKG0kaW5mX3JvdXRlKSkpCmBgYAoKYGBge3J9Cm0kaW5mX3JvdXRlID0gZmFjdG9yKG0kaW5mX3JvdXRlLCBsZXZlbHMgPSBjKCdDb250cm9sJywnSW5kZXgnLCdDb250YWN0JykpCgptID0gbSAlPiUgZmlsdGVyKG5hbWUueCAhPSBpcy5uYShuYW1lLngpKSAlPiUgdW5pcXVlKCkKYGBgCgpgYGB7cn0KcDEgPSBtICU+JSBmaWx0ZXIoIShpcy5uYShwYWlyX251bWJlcnMpKSkgJT4lIHVuaXF1ZSgpICU+JSAKICAgIGdncGxvdCguLCBhZXMoeD0gZHBpLCB5ID0gcGFpcl9udW1iZXJzLCBmaWxsID0gZGlldCkpICsgCiAgICBnZW9tX3RpbGUoY29sb3IgPSAnYmxhY2snKSArIAogICAgUGxvdFRoZW1lMyArCiAgICBEaWV0Y29sU2NhbGVfZmlsbCArIAogICAgZmFjZXRfZ3JpZChwYWlyX2RpZXRzfmluZl9yb3V0ZSwgc2NhbGVzID0gJ2ZyZWUnLCBzcGFjZSA9ICdmcmVlJykKCnByaW50KHAxKQoKZ2dzYXZlKHAxLAogICAgICAgZmlsZW5hbWUgPSBnbHVlKCJ7d2tkaXJ9L0RWR19maWd1cmVzL2ZpbmFsLnNhbXBsZXMucGRmIiksCiAgICAgICB3aWR0aCA9IDYsCiAgICAgICBoZWlnaHQgPSA2LCBsaW1pdHNpemU9RkFMU0UsIHVzZURpbmdiYXRzID0gRkFMU0UpCgpnZ3NhdmUocDEsCiAgICAgICBmaWxlbmFtZSA9IGdsdWUoInt3a2Rpcn0vRFZHX2ZpZ3VyZXMvZmluYWwuc2FtcGxlcy5wbmciKSwKICAgICAgIHdpZHRoID0gNiwKICAgICAgIGhlaWdodCA9IDYsIGxpbWl0c2l6ZT1GQUxTRSkgIywgdXNlRGluZ2JhdHMgPSBGQUxTRSkKYGBgCgpgYGB7cn0KZHZnX3JlcHMgPSBkdmdfcmVwcyAlPiUgCiAgICAgICAgICAgIGZpbHRlcihEVkdfZnJlcS54ID4gY291bnRfY3V0ICYgRFZHX2ZyZXEueSA+IGNvdW50X2N1dCkgJT4lIAogICAgICAgIHVuaXF1ZSgpICAgIyBtYWtlIHN1cmUgdGhhdCBib3RoIHJlcHMgcGFzcyBvdXIgY3V0b2ZmCgojIGFkZCBpbiB2YXJpYWJsZXMgZm9yIHBsb3R0aW5nCmR2Z19yZXBzJGZlcnJldF9kYXkgPSBwYXN0ZTAoZHZnX3JlcHMkZmVycmV0X2lkLCAnXycsIGR2Z19yZXBzJGRwaSkgIAoKbSRmZXJyZXRfZGF5ID0gcGFzdGUwKG0kZmVycmV0X2lkLCAnXycsIG0kZHBpKQpgYGAKCmBgYHtyfQpzdG9ja190ZW1wID0gZHZnX3JlcHMgJT4lIGZpbHRlcihkcGkgPT0gJ3N0b2NrJykgJT4lCiAgICBncm91cF9ieShmZXJyZXRfaWQsIGNvaG9ydCwgZHBpLCBzZWdtZW50LCBuYW1lLngsIG5hbWUueSkgJT4lCiAgICBhZGRfdGFsbHkobmFtZSA9ICdzZWdfZGVsZXRpb25fcmljaG5lc3MnKSAlPiUKICAgIHVuaXF1ZSgpICU+JQogICAgdW5ncm91cCgpICU+JSAKICAgIGdyb3VwX2J5KGZlcnJldF9pZCwgZHBpLCBuYW1lLngsIG5hbWUueSwgY29ob3J0KSAlPiUgCiAgICBhZGRfdGFsbHkobmFtZSA9ICdkZWxldGlvbl9yaWNobmVzcycpICU+JQogICAgdW5ncm91cCgpICU+JSAKICAgIHVuaXF1ZSgpCgpzID0gc3RvY2tfdGVtcCAgIyB3aWxsIHVzZSBsYXRlcgoKIyBmaWx0ZXIgZG93biBzdG9jayB0ZW1wIGluZm9ybWF0aW9uCnN0b2NrX3RlbXAgPSBzdG9ja190ZW1wICU+JSAKICAgICAgICAgICAgc2VsZWN0KGZlcnJldF9pZCwgZHBpLCBjb2hvcnQsZmVycmV0X2RheSwgc2VnbWVudCwgZGVsZXRpb25fcmljaG5lc3MsIHNlZ19kZWxldGlvbl9yaWNobmVzcykgJT4lCiAgICAgICAgICAgIHVuaXF1ZSgpCgoKc3RvY2tfdGVtcCA9IG1lcmdlKHN0b2NrX3RlbXAsIG0sIGJ5ID0gYygnZmVycmV0X2lkJywgJ2RwaScsJ2NvaG9ydCcsJ2ZlcnJldF9kYXknKSkgJT4lIAogICAgdW5pcXVlKCkKYGBgCgpgYGB7cn0KIyBmaWx0ZXIgb3V0IHN0b2NrIGluZm9ybWF0aW9uLCBjYWxjdWxhdGUgZHZnIHJpY2huZXNzIGJ5IHNlZ21lbnQgYW5kIGFjcm9zcyBnZW5vbWUgZm9yIHNhbXBsZXMKZHIgPSBkdmdfcmVwcyAlPiUgCiAgICAgICAgICAgIGZpbHRlcihkcGkgIT0gJ3N0b2NrJykgJT4lIAogICAgICAgICAgICB1bmlxdWUoKSAlPiUgCiAgICAgICAgICAgIGdyb3VwX2J5KGZlcnJldF9pZCwgZHBpLCBzZWdtZW50LCBuYW1lLngsIG5hbWUueSwgY29ob3J0KSAlPiUKICAgICAgICAgICAgYWRkX3RhbGx5KG5hbWUgPSAnc2VnX2RlbGV0aW9uX3JpY2huZXNzJykgJT4lCiAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUgCiAgICAgICAgICAgIGdyb3VwX2J5KGZlcnJldF9pZCwgZHBpLCBuYW1lLngsIG5hbWUueSwgY29ob3J0KSAlPiUgCiAgICAgICAgICAgIGFkZF90YWxseShuYW1lID0gJ2RlbGV0aW9uX3JpY2huZXNzJykgJT4lCiAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUgCiAgICAgICAgICAgIHVuaXF1ZSgpCgojIGZpbHRlciBkb3duIGluZm9ybWF0aW9uIHNvIHlvdSBkb24ndCBoYXZlIGR1cGxpY2F0ZXMKcmljaG5lc3MgPSBkciAlPiUgCiAgICAgICAgICAgIHNlbGVjdChmZXJyZXRfaWQsIGRwaSwgY29ob3J0LGZlcnJldF9kYXksIHNlZ21lbnQsIGRlbGV0aW9uX3JpY2huZXNzLCBzZWdfZGVsZXRpb25fcmljaG5lc3MpICU+JQogICAgICAgICAgICB1bmlxdWUoKQoKIyBtZXJnZSB3aXRoIG1ldGFkYXRhIGluZm8KI3JpY2huZXNzID0gbWVyZ2UocmljaG5lc3MsIG0sIGJ5ID0gYygnZmVycmV0X2lkJywgJ2RwaScsJ2NvaG9ydCcsJ2ZlcnJldF9kYXknKSwgYWxsLnkgPSBUUlVFKSAlPiUgIyBDSEFOR0VECnJpY2huZXNzID0gbWVyZ2UocmljaG5lc3MsIG0sIGJ5ID0gYygnZmVycmV0X2lkJywgJ2RwaScsJ2NvaG9ydCcsJ2ZlcnJldF9kYXknKSwgYWxsLnggPSBUUlVFKSAlPiUKICAgIHVuaXF1ZSgpICU+JSAKICBmaWx0ZXIoIWlzLm5hKGluZl9yb3V0ZSkpCgojIG1ha2Ugc3VyZSB3ZSBmaWx0ZXIgb3V0IHN0b2NrIGluZm9ybWF0aW9uICh3aWxsIGFkZCB1c2luZyB0aGUgJ3MnIGRhdGFmcmFtZSBnZW5lcmF0ZWQgYWJvdmUpCnJpY2huZXNzID0gcmljaG5lc3MgJT4lIGZpbHRlcihkcGkgIT0gJ3N0b2NrJykKCnJlcHNfZGYgPSByYmluZChkciwgcykgJT4lIHVuaXF1ZSgpICMgZmluYWwgcmVwcyByaWNobmVzcyBkZgpyZXBzX2RmID0gbWVyZ2UocmVwc19kZiwgbSwgYnkgPSBjKCdmZXJyZXRfaWQnLCdkcGknLCdjb2hvcnQnLCdmZXJyZXRfZGF5JywnbmFtZS54JywncmVwLngnLCduYW1lLnknLCdyZXAueScpKSAgJT4lIHVuaXF1ZSgpICMgYWRkIG1ldGFkYXRhCmBgYAoKYGBge3J9CnA0ID0gcmVwc19kZiAlPiUgCiAgICBzZWxlY3Qoc2VnbWVudCwgTmV3R2FwLCBFc3RpbWF0ZWRGcmFnTGVuZ3RoLCBkaWV0KSAlPiUKICAgIHVuaXF1ZSgpICU+JQogICAgZ2dwbG90KC4sIGFlcyh4PSBFc3RpbWF0ZWRGcmFnTGVuZ3RoKSkgKyAKICAgIGdlb21faGlzdG9ncmFtKGNvbG9yID0gJ2JsYWNrJykgKyAKICAgIFBsb3RUaGVtZTEgKwogICAgbGFicyh4PSJlc3RpbWF0ZWQgRFZHIGZyYWcuIGxlbmd0aCAobnQpIiwgeT0nbnVtYmVyIG9mIHVuaXF1ZSBEVkcgc3BlY2llcycpIApwcmludChwNCkKCmdnc2F2ZShwNCwKICAgICAgIGZpbGVuYW1lID0gZ2x1ZSgie3drZGlyfS9EVkdfZmlndXJlcy9kZWxldGlvbi5zaXplLnBkZiIpLAogICAgICAgd2lkdGggPSA1LAogICAgICAgaGVpZ2h0ID0gNSwgbGltaXRzaXplPUZBTFNFLCB1c2VEaW5nYmF0cyA9IEZBTFNFKQoKZ2dzYXZlKHA0LAogICAgICAgZmlsZW5hbWUgPSBnbHVlKCJ7d2tkaXJ9L0RWR19maWd1cmVzL2RlbGV0aW9uLnNpemUucG5nIiksCiAgICAgICB3aWR0aCA9NSwKICAgICAgIGhlaWdodCA9IDUsIGxpbWl0c2l6ZT1GQUxTRSkgIywgdXNlRGluZ2JhdHMgPSBGQUxTRSkKCnA0X2FsdCA9IHJlcHNfZGYgJT4lIAogICAgc2VsZWN0KHNlZ21lbnQsIE5ld0dhcCwgRXN0aW1hdGVkRnJhZ0xlbmd0aCwgZGlldCwgaW5mX3JvdXRlKSAlPiUKICAgIHVuaXF1ZSgpICU+JQogICAgZ2dwbG90KC4sIGFlcyh4PSBFc3RpbWF0ZWRGcmFnTGVuZ3RoKSkgKyAKICAgIGdlb21faGlzdG9ncmFtKGNvbG9yID0gJ2JsYWNrJywgYmlud2lkdGggPSA1MCkgKyAKICAgIGZhY2V0X2dyaWQoaW5mX3JvdXRlfmRpZXQpICsKICAgIFBsb3RUaGVtZTEgKwogICAgbGFicyh4PSJlc3RpbWF0ZWQgRFZHIGZyYWcuIGxlbmd0aCAobnQpIiwgeT0nbnVtYmVyIG9mIHVuaXF1ZSBEVkcgc3BlY2llcycpIApwcmludChwNF9hbHQpCmdnc2F2ZShwNF9hbHQsCiAgICAgICBmaWxlbmFtZSA9IGdsdWUoInt3a2Rpcn0vRFZHX2ZpZ3VyZXMvZGVsZXRpb24uc2l6ZS5ieWRpZXQuYnl0eXBlLnBkZiIpLAogICAgICAgd2lkdGggPSAxMCwKICAgICAgIGhlaWdodCA9IDUsIGxpbWl0c2l6ZT1GQUxTRSwgdXNlRGluZ2JhdHMgPSBGQUxTRSkKCmBgYAoKYGBge3J9CmxlYW5faW5kZXggPSAgcmVwc19kZiAlPiUgZmlsdGVyKGluZl9yb3V0ZSA9PSAnSW5kZXgnICYgZGlldCA9PSAnTGVhbicpICU+JSAKICAgICAgICAgICAgICAgIHVuaXF1ZSgpICU+JQogICAgICAgICAgICAgICAgZ3JvdXBfYnkoTmV3R2FwLCBzZWdtZW50LCBOZXdTdGFydCwgTmV3RW5kKSAlPiUKICAgICAgICAgICAgYWRkX3RhbGx5KG5hbWUgPSAnbGVhbl9kZWxldGlvbl9jb3VudCcpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgc2VsZWN0KE5ld0dhcCwgc2VnbWVudCwgbGVhbl9kZWxldGlvbl9jb3VudCkgJT4lCiAgICB1bmlxdWUoKQoKCm9iZXNlX2luZGV4ID0gIHJlcHNfZGYgJT4lIGZpbHRlcihpbmZfcm91dGUgPT0gJ0luZGV4JyAmIGRpZXQgPT0gJ09iZXNlJykgJT4lIAogICAgICAgICAgICAgICAgdW5pcXVlKCkgJT4lCiAgICAgICAgICAgICAgICBncm91cF9ieShOZXdHYXAsIHNlZ21lbnQsIE5ld1N0YXJ0LCBOZXdFbmQpICU+JQogICAgICAgICAgICBhZGRfdGFsbHkobmFtZSA9ICdvYmVzZV9kZWxldGlvbl9jb3VudCcpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgc2VsZWN0KE5ld0dhcCwgc2VnbWVudCwgb2Jlc2VfZGVsZXRpb25fY291bnQpICU+JQogICAgdW5pcXVlKCkKCgpkZiA9IG1lcmdlKGxlYW5faW5kZXgsIG9iZXNlX2luZGV4LCBieSA9IGMoJ05ld0dhcCcsJ3NlZ21lbnQnKSwgYWxsID0gVFJVRSkgCgpoZWFkKGRmKQoKZGYkbGVhbl9kZWxldGlvbl9jb3VudFtpcy5uYShkZiRsZWFuX2RlbGV0aW9uX2NvdW50KV0gPSAwCgpkZiRvYmVzZV9kZWxldGlvbl9jb3VudFtpcy5uYShkZiRvYmVzZV9kZWxldGlvbl9jb3VudCldID0gMApgYGAKCmBgYHtyfQpwOCA9IHJlcHNfZGYgJT4lIGZpbHRlcihpbmZfcm91dGUgPT0gJ0luZGV4JykgJT4lIAogICAgICAgICAgICAgICAgdW5pcXVlKCkgJT4lCiAgICAgICAgICAgICAgICBncm91cF9ieShOZXdHYXAsIHNlZ21lbnQsIE5ld1N0YXJ0LCBOZXdFbmQpICU+JQogICAgICAgICAgICBhZGRfdGFsbHkobmFtZSA9ICdzYW1wbGVfY291bnQnKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIHNlbGVjdChOZXdHYXAsIHNlZ21lbnQsc2FtcGxlX2NvdW50KSAlPiUKICAgIHVuaXF1ZSgpICAlPiUKICAgIGdncGxvdCguLCBhZXMoeD1zYW1wbGVfY291bnQsIHkgPSAuLmNvdW50Li4vc3VtKC4uY291bnQuLikpKSArCiAgICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9J2JsYWNrJykgKyAKICAgIGxhYnMoeD0nbnVtYmVyIG9mIHNhbXBsZXMgd2l0aCBEVkcgdHlwZScsIHk9J3Byb3BvcnRpb24gb2YgRFZHcyBpbiBkYXRhc2V0IChpbmRleCBvbmx5KScpICsgCiAgICBQbG90VGhlbWUxIAoKcHJpbnQocDgpCmdnc2F2ZShwOCwKICAgICAgIGZpbGVuYW1lID0gZ2x1ZSgie3drZGlyfS9EVkdfZmlndXJlcy9zYW1wbGUuY291bnQuaGlzdG8ucGRmIiksCiAgICAgICB3aWR0aCA9IDUsCiAgICAgICBoZWlnaHQgPSA1LCBsaW1pdHNpemU9RkFMU0UsIHVzZURpbmdiYXRzID0gRkFMU0UpCgpnZ3NhdmUocDgsCiAgICAgICBmaWxlbmFtZSA9IGdsdWUoInt3a2Rpcn0vRFZHX2ZpZ3VyZXMvc2FtcGxlLmNvdW50Lmhpc3RvLnBuZyIpLAogICAgICAgd2lkdGggPTUsCiAgICAgICBoZWlnaHQgPSA1LCBsaW1pdHNpemU9RkFMU0UpICMsIHVzZURpbmdiYXRzID0gRkFMU0UpCmBgYAoKYGBge3J9CnJlcHNfZGYkYXZlX2R2Z19mcmVxID0gKHJlcHNfZGYkRFZHX2ZyZXEueCArIHJlcHNfZGYkRFZHX2ZyZXEueSkvMgpgYGAKCmBgYHtyfQpyZXBzX2RmID0gcmVwc19kZiAlPiUKICBhcnJhbmdlKGZlcnJldF9kYXksIGF2ZV9kdmdfZnJlcSkgJT4lIAogIGdyb3VwX2J5KGZlcnJldF9kYXkpICU+JSAKICBtdXRhdGUob3JkZXJfbnVtYmVyID0gcm93X251bWJlcigpKSAlPiUgCiAgdW5ncm91cCgpICU+JQogIHVuaXF1ZSgpCmBgYAoKYGBge3J9CnJlcHNfZGYgJT4lIAogICAgZ3JvdXBfYnkoTmV3R2FwLCBzZWdtZW50LCBpbmZfcm91dGUsIGRpZXQpICU+JQogICAgbXV0YXRlKG1lYW5fb3JkZXIgPSBtZWFuKG9yZGVyX251bWJlciksCiAgICAgICAgICBzYW1wbGVfY291bnQgPSBuKCksCiAgICAgICAgICBtaW5fb3JkZXIgPSBtaW4ob3JkZXJfbnVtYmVyKSwKICAgICAgICAgIG1heF9vcmRlciA9IG1heChvcmRlcl9udW1iZXIpLAogICAgICAgICAgbWVkaWFuX29yZCA9IG1lZGlhbihvcmRlcl9udW1iZXIpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIHVuaXF1ZSgpICU+JQogICAgc2VsZWN0KHNlZ21lbnQsIE5ld0dhcCwgbWVhbl9vcmRlciwgc2FtcGxlX2NvdW50LCBtaW5fb3JkZXIsIG1heF9vcmRlciwgbWVkaWFuX29yZCwgaW5mX3JvdXRlLCBkaWV0KSAlPiUKICAgIGZpbHRlcihzYW1wbGVfY291bnQgPiAxKSAlPiUKICAgIHVuaXF1ZSgpICU+JQogICAgZ2dwbG90KC4sIGFlcyh5PW1lYW5fb3JkZXIsIHggPSBzYW1wbGVfY291bnQpKSArIAogICAgZ2VvbV9wb2ludCgpICsgCiAgICBQbG90VGhlbWUxICsgCiAgICBmYWNldF9ncmlkKC5+ZGlldCArIGluZl9yb3V0ZSkKYGBgCgpgYGB7cn0KdG9wX3RlbiA9IHJlcHNfZGYgJT4lIGZpbHRlcihvcmRlcl9udW1iZXIgJWluJSBjKDEsIDIsMyAsNCwgNSwgNiwgNywgOCwgOSwgMTApKSAlPiUgdW5pcXVlKCkKCmhlYWQodG9wX3RlbikKCmxlbmd0aChsZXZlbHMoZmFjdG9yKHRvcF90ZW4kTmV3R2FwKSkpCmBgYAoKYGBge3J9Cm1heChkZiRsZWFuX2RlbGV0aW9uX2NvdW50KQptYXgoZGYkb2Jlc2VfZGVsZXRpb25fY291bnQpCgpwOSA9IGdncGxvdChkZiwgYWVzKHg9bGVhbl9kZWxldGlvbl9jb3VudCwgeSA9IG9iZXNlX2RlbGV0aW9uX2NvdW50KSkgKyAKICAgIGdlb21faml0dGVyKHdpZHRoID0gMC4xLCBoZWlnaHQgPSAwLjEsIGFscGhhID0gMC4zKSArIAogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyLCBjb2xvciA9ICdibGFjaycpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDI1LCBsaW5ldHlwZSA9IDIsIGNvbG9yID0gJ3JlZCcpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMiwgY29sb3IgPSAnYmxhY2snKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxNywgbGluZXR5cGUgPSAyLCBjb2xvciA9ICdyZWQnKSArCiAgICBsYWJzKHg9ICdudW1iZXIgb2YgbGVhbiBzYW1wbGVzIHdpdGggRFZHJywgeT0nbnVtYmVyIG9mIG9iZXNlIHNhbXBsZXMgd2l0aCBEVkcnKSArIAogICAgUGxvdFRoZW1lMSAKCnByaW50KHA5KQpnZ3NhdmUocDksCiAgICAgICBmaWxlbmFtZSA9IGdsdWUoInt3a2Rpcn0vRFZHX2ZpZ3VyZXMvc2FtcGxlLmNvdW50LmxlYW4udi5vYmVzZS5wZGYiKSwKICAgICAgIHdpZHRoID0gNSwKICAgICAgIGhlaWdodCA9IDUsIGxpbWl0c2l6ZT1GQUxTRSwgdXNlRGluZ2JhdHMgPSBGQUxTRSkKCmdnc2F2ZShwOSwKICAgICAgIGZpbGVuYW1lID0gZ2x1ZSgie3drZGlyfS9EVkdfZmlndXJlcy9zYW1wbGUuY291bnQubGVhbi52Lm9iZXNlLnBuZyIpLAogICAgICAgd2lkdGggPTUsCiAgICAgICBoZWlnaHQgPSA1LCBsaW1pdHNpemU9RkFMU0UpICMsIHVzZURpbmdiYXRzID0gRkFMU0UpCmBgYAoKYGBge3J9CnJpY2huZXNzID0gcmJpbmQocmljaG5lc3MsIHN0b2NrX3RlbXApCiNyaWNobmVzcyRkZWxldGlvbl9yaWNobmVzc1tpcy5uYShyaWNobmVzcyRkZWxldGlvbl9yaWNobmVzcyldID0gMAoKREFZUyA9IGMoJ3N0b2NrJywnZDAyJywnZDA0JywnZDA2JywnZDA4JywnZDEwJywnZDEyJykKYGBgCgpgYGB7cn0KcmljaG5lc3MkZHBpID0gZmFjdG9yKHJpY2huZXNzJGRwaSwgbGV2ZWxzID0gREFZUykKcmljaG5lc3MgJT4lIGZpbHRlcihkcGkgJWluJSBjKCdkMDInLCdkMDQnKSkgJT4lCiAgICAgICAgZmlsdGVyKGluZl9yb3V0ZSA9PSAnSW5kZXgnIHwgaW5mX3JvdXRlID09ICdDb250cm9sJykgJT4lCiAgICAgICAgZmlsdGVyKCEoaXMubmEoaW5mX3JvdXRlKSkpICU+JQogICAgc2VsZWN0KGZlcnJldF9pZCwgZHBpLCBkZWxldGlvbl9yaWNobmVzcywgaW5mX3JvdXRlLCBkaWV0LCBwYWlyX2RpZXRzLCBjb2hvcnQpICU+JQogICAgdW5pcXVlKCkgJT4lCiAgICBncm91cF9ieShmZXJyZXRfaWQpICU+JQogICAgYWRkX3RhbGx5KG5hbWUgPSAnbicpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgZmlsdGVyKG4gPj0gMikgJT4lIAogICAgdW5ncm91cCgpICU+JQogICAgdW5pcXVlKCkgJT4lCiAgICBnZ3Bsb3QoLiwgYWVzKHg9ZHBpLCB5ID0gZGVsZXRpb25fcmljaG5lc3MsIGNvbG9yID0gY29ob3J0LCBncm91cD1mZXJyZXRfaWQsIHNoYXBlID0gZGlldCkpICsgCiAgICAjZ2VvbV9ib3hwbG90KCkgKyAKICAgIGdlb21fbGluZSgpICsgCiAgICBnZW9tX3BvaW50KHNpemUgPSAyKSArIAogICAgUGxvdFRoZW1lMSArCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICdTZXQxJykKICAgICNEaWV0Y29sU2NhbGUgKyAKICAgICNmYWNldF9ncmlkKC5+Y29ob3J0KQoKCnA3ID0gcmljaG5lc3MgJT4lIGZpbHRlcihkcGkgJWluJSBjKCdkMDInLCdkMDQnLCdkMDYnKSkgJT4lCiAgICAgICAgZmlsdGVyKGluZl9yb3V0ZSA9PSAnSW5kZXgnIHwgaW5mX3JvdXRlID09ICdDb250cm9sJykgJT4lICAgIAogICAgc2VsZWN0KGZlcnJldF9pZCwgZHBpLCBkZWxldGlvbl9yaWNobmVzcywgaW5mX3JvdXRlLCBkaWV0LCBwYWlyX2RpZXRzLCBjb2hvcnQpICU+JQogICAgdW5pcXVlKCkgJT4lCiAgICBncm91cF9ieShmZXJyZXRfaWQpICU+JQogICAgYWRkX3RhbGx5KG5hbWUgPSAnbicpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgZmlsdGVyKG4gPj0gMikgJT4lIAogICAgdW5ncm91cCgpICU+JQogICAgdW5pcXVlKCkgJT4lCiAgICBnZ3Bsb3QoLiwgYWVzKHg9ZHBpLCB5ID0gZGVsZXRpb25fcmljaG5lc3MsIGNvbG9yID0gZGlldCwgZ3JvdXA9ZmVycmV0X2lkLCBzaGFwZSA9IGRpZXQpKSArIAogICAgI2dlb21fYm94cGxvdCgpICsgCiAgICBnZW9tX2xpbmUoKSArIAogICAgZ2VvbV9wb2ludChzaXplID0gMikgKyAKICAgIFBsb3RUaGVtZTEgKwogICAgRGlldGNvbFNjYWxlCiAgICAjZmFjZXRfZ3JpZCgufmNvaG9ydCkKCnByaW50KHA3KQpnZ3NhdmUocDcsCiAgICAgICBmaWxlbmFtZSA9IGdsdWUoInt3a2Rpcn0vRFZHX2ZpZ3VyZXMvcmljaG5lc3MuaW5kZXgucGRmIiksCiAgICAgICB3aWR0aCA9IDUsCiAgICAgICBoZWlnaHQgPSA1LCBsaW1pdHNpemU9RkFMU0UsIHVzZURpbmdiYXRzID0gRkFMU0UpCgpnZ3NhdmUocDcsCiAgICAgICBmaWxlbmFtZSA9IGdsdWUoInt3a2Rpcn0vRFZHX2ZpZ3VyZXMvcmljaG5lc3MuaW5kZXgucG5nIiksCiAgICAgICB3aWR0aCA9NSwKICAgICAgIGhlaWdodCA9IDUsIGxpbWl0c2l6ZT1GQUxTRSkgIywgdXNlRGluZ2JhdHMgPSBGQUxTRSkKYGBgCgpgYGB7cn0KY29sbmFtZXMocmljaG5lc3MpCm9yZGVyX3R5cGVkYXkgPSBjKCdDb250cm9sX3N0b2NrJywKICAgICAgICAgICAgICAgICAgJ0luZGV4X2QwMicsJ0luZGV4X2QwNCcsJ0luZGV4X2QwNicsJ0luZGV4X2QwOCcsJ0luZGV4X2QxMCcsJ0luZGV4X2QxMicsCiAgICAgICAgICAgICAgICAgICdDb250YWN0X2QwMicsJ0NvbnRhY3RfZDA0JywnQ29udGFjdF9kMDYnLCdDb250YWN0X2QwOCcsJ0NvbnRhY3RfZDEwJywnQ29udGFjdF9kMTInKQpgYGAKCmBgYHtyfQpyaWNobmVzcyR0eXBlX2RheSA9IHBhc3RlMChyaWNobmVzcyRpbmZfcm91dGUsICdfJywgcmljaG5lc3MkZHBpKQpyaWNobmVzcyR0eXBlX2RheSA9IGZhY3RvcihyaWNobmVzcyR0eXBlX2RheSwgbGV2ZWxzID0gb3JkZXJfdHlwZWRheSkKCnAyID0gcmljaG5lc3MgJT4lIGZpbHRlcihkaWV0ID09ICdPYmVzZScgJiBwYWlyX2RpZXRzID09ICdPQj5PQicpICU+JQogICAgc2VsZWN0KGZlcnJldF9pZCwgZHBpLCBkZWxldGlvbl9yaWNobmVzcywgaW5mX3JvdXRlLCBkaWV0LCBwYWlyX251bWJlcnMsIHBhaXJfZGlldHMsIHR5cGVfZGF5KSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIHVuaXF1ZSgpICU+JQogICAgZ2dwbG90KC4sIGFlcyh4PXR5cGVfZGF5LCB5ID0gZGVsZXRpb25fcmljaG5lc3MsIGNvbG9yID0gcGFpcl9udW1iZXJzLCBncm91cD1wYWlyX251bWJlcnMpKSArIAogICAgI2dlb21fYm94cGxvdCgpICsgCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsgCiAgICBnZW9tX3BvaW50KHNpemUgPSAyKSArIAogICAgbGFicyh4PSdkcGkgKGJ5IGluZGV4IGNhc2UpJywgeT0nRFZHIHJpY2huZXNzJykgKyAKICAgIFBsb3RUaGVtZTEgKwogICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAnU2V0MicpICMrCiAgICAjRGlldGNvbFNjYWxlICsgCiAgICAjZmFjZXRfZ3JpZCgufmluZl9yb3V0ZSkKCnByaW50KHAyKQpnZ3NhdmUocDIsCiAgICAgICBmaWxlbmFtZSA9IGdsdWUoInt3a2Rpcn0vRFZHX2ZpZ3VyZXMvb2Jlc2UudG8ub2Jlc2UuZGl2ZXJzaXR5LnBkZiIpLAogICAgICAgd2lkdGggPSA4LAogICAgICAgaGVpZ2h0ID0gNiwgbGltaXRzaXplPUZBTFNFLCB1c2VEaW5nYmF0cyA9IEZBTFNFKQoKZ2dzYXZlKHAyLAogICAgICAgZmlsZW5hbWUgPSBnbHVlKCJ7d2tkaXJ9L0RWR19maWd1cmVzL29iZXNlLnRvLm9iZXNlLmRpdmVyc2l0eS5wbmciKSwKICAgICAgIHdpZHRoID04LAogICAgICAgaGVpZ2h0ID0gNiwgbGltaXRzaXplPUZBTFNFKSAjLCB1c2VEaW5nYmF0cyA9IEZBTFNFKQpgYGAKCmBgYHtyfQpnZW5fcmljaCA9IHJpY2huZXNzICU+JSAKICBzZWxlY3QoZmVycmV0X2lkLCBkcGksIGNvaG9ydCxkZWxldGlvbl9yaWNobmVzcywgaW5mX3JvdXRlLCBkaWV0LCBwYWlyX251bWJlcnMsIHBhaXJfZGlldHMsIHR5cGVfZGF5KSAlPiUKICB1bmlxdWUoKQoKaGVhZChnZW5fcmljaCkKCmdlbl9yaWNoICU+JSBmaWx0ZXIoZHBpICVpbiUgYygnZDAyJywnZDA0JywnZDA2Jywnc3RvY2snKSkgJT4lCiAgICBmaWx0ZXIoaW5mX3JvdXRlID09ICdJbmRleCcgfCBpbmZfcm91dGUgPT0gIkNvbnRyb2wiKSAlPiUKICAgIGdncGxvdCguLCBhZXMoeD1kaWV0LCB5ID0gZGVsZXRpb25fcmljaG5lc3MsIGdyb3VwID0gZGlldCkpICsgCiAgICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArIAogICAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjIsIGFlcyhjb2xvciA9IGRpZXQpKSArCiAgICBsYWJzKHg9J3NlZ21lbnQnLHk9J2RlbGV0aW9uIHJpY2huZXNzJykgKyAKICAgIFBsb3RUaGVtZTEgKwogICAgRGlldGNvbFNjYWxlICsKICAgIGZhY2V0X2dyaWQoLn5kcGkpCmBgYAoKVGVzdCBmb3Igc2lnbmlmaWNhbmNlCmBgYHtyfQpvID0gZmlsdGVyKGdlbl9yaWNoLCBpbmZfcm91dGUgPT0gIkluZGV4IiAmIGRwaSA9PSAiZDA2IiAmIGRpZXQgPT0gIk9iZXNlIikKbCA9IGZpbHRlcihnZW5fcmljaCwgaW5mX3JvdXRlID09ICJJbmRleCIgJiBkcGkgPT0gImQwNiIgJiBkaWV0ID09ICJMZWFuIikKdC50ZXN0KG8kZGVsZXRpb25fcmljaG5lc3MsbCRkZWxldGlvbl9yaWNobmVzcykKYGBgCgpgYGB7cn0Kc2VnX3JpY2ggPSByaWNobmVzcyAlPiUgI2ZpbHRlcihkaWV0ID09ICdvYmVzZScgJiBwYWlyX2RpZXRzID09ICdvYmVzZV9vYmVzZScpICU+JQogICAgc2VsZWN0KGZlcnJldF9pZCwgZHBpLCBzZWdfZGVsZXRpb25fcmljaG5lc3MsIGluZl9yb3V0ZSwgZGlldCwgCiAgICAgICAgICAgcGFpcl9udW1iZXJzLCBwYWlyX2RpZXRzLCB0eXBlX2RheSwgc2VnbWVudCkgJT4lCiAgICB1bmlxdWUoKQoKaGVhZChzZWdfcmljaCkKCnRlbXAgPSBzZWdfcmljaCAlPiUgc2VsZWN0KGZlcnJldF9pZCwgZHBpLCBpbmZfcm91dGUsIGRpZXQsIHBhaXJfbnVtYmVycywgdHlwZV9kYXksIHBhaXJfZGlldHMpICU+JSB1bmlxdWUoKQp0ZW1wJEg5TjJfUEIyID0gMAp0ZW1wJEg5TjJfUEIxID0gMAp0ZW1wJEg5TjJfUEEgPSAwCnRlbXAkSDlOMl9IQSA9IDAKdGVtcCRIOU4yX05QID0gMAp0ZW1wJEg5TjJfTkEgPSAwCnRlbXAkSDlOMl9NUCA9IDAKdGVtcCRIOU4yX05TID0gMAoKdGVtcCA9IHBpdm90X2xvbmdlcih0ZW1wLCBjb2xzID0gYWxsX29mKFNFR01FTlRTKSwgbmFtZXNfdG8gPSAnc2VnbWVudCcpICU+JSBzZWxlY3QoLXZhbHVlKQoKc2VnX3JpY2ggPSBtZXJnZShzZWdfcmljaCwgdGVtcCwgYnkgPSBjKCdmZXJyZXRfaWQnLCAnZHBpJywgJ2luZl9yb3V0ZScsICdkaWV0JywgCiAgICAgICAgICAgJ3BhaXJfbnVtYmVycycsICdwYWlyX2RpZXRzJywgJ3R5cGVfZGF5JywgJ3NlZ21lbnQnKSwgYWxsID0gVFJVRSkgCgojc2VnX3JpY2gkc2VnX2RlbGV0aW9uX3JpY2huZXNzW2lzLm5hKHNlZ19yaWNoJHNlZ19kZWxldGlvbl9yaWNobmVzcyldID0gMAoKc2VnX3JpY2gkc2VnbWVudCA9IGZhY3RvcihzZWdfcmljaCRzZWdtZW50LCBsZXZlbHMgPSBTRUdNRU5UUykKaGVhZChzZWdfcmljaCkKYGBgCgpgYGB7cn0Kc2VnX3JpY2ggJT4lIGZpbHRlcihmZXJyZXRfaWQgPT0gMTc4NykgJT4lIGhlYWQoKQpyaWNobmVzcyAlPiUgZmlsdGVyKGZlcnJldF9pZCA9PSAxNzg3KSAlPiUgaGVhZCgpCnRlbXAgJT4lIGZpbHRlcihmZXJyZXRfaWQgPT0gMTc4NykKCmBgYAoKYGBge3J9CnAzID0gc2VnX3JpY2ggJT4lIGZpbHRlcihzZWdtZW50ICVpbiUgU0VHTUVOVFMpICU+JQogICAgZ2dwbG90KC4sIGFlcyh4PXNlZ21lbnQsIHkgPSBzZWdfZGVsZXRpb25fcmljaG5lc3MpKSArIAogICAgZ2VvbV9ib3hwbG90KCkgKyAKICAgIGxhYnMoeD0nc2VnbWVudCcseT0nZGVsZXRpb24gcmljaG5lc3MnKSArIAogICAgUGxvdFRoZW1lMSAKCnByaW50KHAzKQoKZ2dzYXZlKHAzLAogICAgICAgZmlsZW5hbWUgPSBnbHVlKCJ7d2tkaXJ9L0RWR19maWd1cmVzL3NlZ21lbnQucmljaG5lc3MucGRmIiksCiAgICAgICB3aWR0aCA9IDUsCiAgICAgICBoZWlnaHQgPSA1LCBsaW1pdHNpemU9RkFMU0UsIHVzZURpbmdiYXRzID0gRkFMU0UpCgpnZ3NhdmUocDMsCiAgICAgICBmaWxlbmFtZSA9IGdsdWUoInt3a2Rpcn0vRFZHX2ZpZ3VyZXMvc2VnbWVudC5yaWNobmVzcy5wbmciKSwKICAgICAgIHdpZHRoID01LAogICAgICAgaGVpZ2h0ID0gNSwgbGltaXRzaXplPUZBTFNFKSAjLCB1c2VEaW5nYmF0cyA9IEZBTFNFKQpgYGAKCmBgYHtyfQpzZWdfcmljaCRzZWdfd2VpZ2h0ID0gcGFzdGUwKHNlZ19yaWNoJHNlZ21lbnQsICdfJywgc2VnX3JpY2gkZGlldCkKc2VnX3JpY2gkZGlldCA9IGZhY3RvcihzZWdfcmljaCRkaWV0LCBsZXZlbHMgPSBjKCdDb250cm9sJywnTGVhbicsJ09iZXNlJykpCmBgYAoKYGBge3J9CnNlZ19yaWNoICU+JSBmaWx0ZXIoc2VnbWVudCAlaW4lIFNFR01FTlRTKSAlPiUKICAgIGRyb3BfbmEoaW5mX3JvdXRlKSAlPiUgCiAgICBnZ3Bsb3QoLiwgYWVzKHg9c2VnbWVudCwgeSA9IHNlZ19kZWxldGlvbl9yaWNobmVzcywgZ3JvdXAgPSBzZWdfd2VpZ2h0LCBjb2xvciA9IGRpZXQpKSArIAogICAgZ2VvbV9ib3hwbG90KCkgKyAKICAgIGxhYnMoeD0nc2VnbWVudCcseT0nZGVsZXRpb24gcmljaG5lc3MnKSArIAogICAgUGxvdFRoZW1lMSArCiAgICBEaWV0Y29sU2NhbGUgKwogICAgZmFjZXRfZ3JpZCgufmluZl9yb3V0ZSkKCgpwNiA9IHNlZ19yaWNoICU+JSBmaWx0ZXIoc2VnbWVudCAlaW4lIFNFR01FTlRTICYgZHBpICVpbiUgYygnZDAyJywnZDA0JywnZDA2Jywnc3RvY2snKSkgJT4lCiAgICBmaWx0ZXIoaW5mX3JvdXRlID09ICdJbmRleCcgfCBpbmZfcm91dGUgPT0gIkNvbnRyb2wiKSAlPiUKICAgIGdncGxvdCguLCBhZXMoeD1zZWdtZW50LCB5ID0gc2VnX2RlbGV0aW9uX3JpY2huZXNzLCBncm91cCA9IHNlZ193ZWlnaHQsIGNvbG9yID0gZGlldCkpICsgCiAgICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArIAogICAgbGFicyh4PSdzZWdtZW50Jyx5PSdkZWxldGlvbiByaWNobmVzcycpICsgCiAgICBQbG90VGhlbWUxICsKICAgIERpZXRjb2xTY2FsZSArCiAgICBmYWNldF9ncmlkKC5+ZHBpKQoKcHJpbnQocDYpCgpnZ3NhdmUocDYsCiAgICAgICBmaWxlbmFtZSA9IGdsdWUoInt3a2Rpcn0vRFZHX2ZpZ3VyZXMvc2VnbWVudC5pbmRleC5yaWNobmVzcy5wZGYiKSwKICAgICAgIHdpZHRoID0gOCwKICAgICAgIGhlaWdodCA9IDQsIGxpbWl0c2l6ZT1GQUxTRSwgdXNlRGluZ2JhdHMgPSBGQUxTRSkKCmdnc2F2ZShwNiwKICAgICAgIGZpbGVuYW1lID0gZ2x1ZSgie3drZGlyfS9EVkdfZmlndXJlcy9zZWdtZW50LmluZGV4LnJpY2huZXNzLnBuZyIpLAogICAgICAgd2lkdGggPTgsCiAgICAgICBoZWlnaHQgPSA0LCBsaW1pdHNpemU9RkFMU0UpICMsIHVzZURpbmdiYXRzID0gRkFMU0UpCgoKYGBgCmBgYHtyfQojIDE5NzMsIDE5NzcsIGFuZCAxOTg2IGFyZSBsaXN0ZWQgYXMgb2Jlc2Ugd2hlbiB0aGV5IGFyZSBhY3R1YWxseSBsZWFuLCBhbmQgMTk4NCBpcyBsaXN0ZWQgYXMgbGVhbiB3aGVuIGl0IGlzIGFjdHVhbGx5IG9iZXNlCgpzZWdfcmljaCAlPiUgCiAgICAjZmlsdGVyKCFpbmZfcm91dGUgJWluJSBjKCdzdG9jaycsJ2xlYW4nLCdvYmVzZScpKSAlPiUgCiAgICBkcm9wX25hKGluZl9yb3V0ZSkgJT4lCiAgICBmaWx0ZXIoZmVycmV0X2lkID09IDE0MDgpCgpvbGRfb2Jlc2UgPSBmaWx0ZXIoc2VnX3JpY2gsIGZlcnJldF9pZCAlaW4lIGMoMTk3MywgMTk3NywgMTk4NikpICU+JSB1bmlxdWUoKQpvbGRfb2Jlc2UkZGlldCA9ICJPYmVzZSIKb2xkX2xlYW4gPSBmaWx0ZXIoc2VnX3JpY2gsZmVycmV0X2lkID09IDE5ODQpICU+JSB1bmlxdWUoKQpvbGRfbGVhbiRkaWV0ID0gIkxlYW4iCm9sZF9zYW1lID0gZmlsdGVyKHNlZ19yaWNoLCBmZXJyZXRfaWQgIT0gYygxOTczLCAxOTc3LCAxOTg2LCAxOTg0KSkKCmRlbGV0ZWl0ID0gcmJpbmQob2xkX29iZXNlLG9sZF9sZWFuLG9sZF9zYW1lKQoKZGVsZXRlaXQgJT4lIGZpbHRlcighZmVycmV0X2lkICVpbiUgYygxOTczLCAxOTc3LDE5ODYsIDE5ODQpICYKICAgICAgICAgICAgICAgICAgICAgIHNlZ21lbnQgJWluJSBTRUdNRU5UUyAmIGRwaSAlaW4lIGMoJ2QwMicsJ2QwNCcsJ2QwNicsJ3N0b2NrJykpICU+JQogICAgZHJvcF9uYShpbmZfcm91dGUpICU+JQogICAgZmlsdGVyKGluZl9yb3V0ZSA9PSAnSW5kZXgnIHwgaW5mX3JvdXRlID09ICJDb250cm9sIikgJT4lCiAgICBnZ3Bsb3QoLiwgYWVzKHg9c2VnbWVudCwgeSA9IHNlZ19kZWxldGlvbl9yaWNobmVzcywgZ3JvdXAgPSBzZWdfd2VpZ2h0LCBjb2xvciA9IGRpZXQpKSArIAogICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKyAKICAgIGxhYnMoeD0nc2VnbWVudCcseT0nZGVsZXRpb24gcmljaG5lc3MnKSArIAogICAgUGxvdFRoZW1lMSArCiAgICBEaWV0Y29sU2NhbGUgKwogICAgZmFjZXRfZ3JpZCgufmRwaSkKCiNzZWdfcmljaCAlPiUgZmlsdGVyKGZlcnJldF9pZCAlaW4lIGMoMTk3MywgMTk3NywxOTg2LCAxOTg0KSAmIGRwaSA9PSAnZDA2JykgJT4lIAojICBzZWxlY3QoZmVycmV0X2lkLCBzZWdtZW50LCBkcGksIHNlZ19kZWxldGlvbl9yaWNobmVzcykgCgpgYGAKVGVzdCBmb3Igc2lnbmlmaWNhbmNlCmBgYHtyfQpvID0gZmlsdGVyKHNlZ19yaWNoLCBpbmZfcm91dGUgPT0gIkluZGV4IiAmIGRwaSA9PSAiZDA2IiAmIHNlZ21lbnQgPT0gIkg5TjJfUEIyIiAmIGRpZXQgPT0gIk9iZXNlIikKbCA9IGZpbHRlcihzZWdfcmljaCwgaW5mX3JvdXRlID09ICJJbmRleCIgJiBkcGkgPT0gImQwNiIgJiBzZWdtZW50ID09ICJIOU4yX1BCMiIgJiBkaWV0ID09ICJMZWFuIikKdC50ZXN0KG8kc2VnX2RlbGV0aW9uX3JpY2huZXNzLGwkc2VnX2RlbGV0aW9uX3JpY2huZXNzKQpgYGAKCmBgYHtyfQpzZWdfcmljaCAlPiUgZmlsdGVyKGluZl9yb3V0ZSA9PSAnSW5kZXgnICYgIHNlZ21lbnQgJWluJSBTRUdNRU5UUykgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICB1bmlxdWUoKSAlPiUKICAgIGdncGxvdCguLCBhZXMoeD10eXBlX2RheSwgeSA9IHNlZ19kZWxldGlvbl9yaWNobmVzcywgY29sb3IgPSBzZWdtZW50LCBncm91cD1zZWdtZW50KSkgKyAKICAgICNnZW9tX2JveHBsb3QoKSArIAogICAgZ2VvbV9saW5lKHNpemUgPSAxKSArIAogICAgZ2VvbV9wb2ludChzaXplID0gMikgKyAKICAgIGxhYnMoeD0nZHBpIChieSBpbmRleCBjYXNlKScsIHk9J0RWRyByaWNobmVzcycpICsgCiAgICBQbG90VGhlbWUxICsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gJ1NldDInKSArCiAgICAjRGlldGNvbFNjYWxlICsgCiAgICBmYWNldF9ncmlkKC5+ZGlldCArIGZlcnJldF9pZCwgc2NhbGVzID0gJ2ZyZWUnLCBzcGFjZSA9ICdmcmVlJykKYGBgCgpgYGB7cn0KcDQgPSBzZWdfcmljaCAlPiUgZmlsdGVyKGRpZXQgPT0gJ09iZXNlJyAmIHBhaXJfZGlldHMgPT0gJ09CPk9CJyAmIHNlZ21lbnQgJWluJSBTRUdNRU5UUykgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICB1bmlxdWUoKSAlPiUKICAgIGdncGxvdCguLCBhZXMoeD10eXBlX2RheSwgeSA9IHNlZ19kZWxldGlvbl9yaWNobmVzcywgY29sb3IgPSBzZWdtZW50LCBncm91cD1zZWdtZW50KSkgKyAKICAgICNnZW9tX2JveHBsb3QoKSArIAogICAgZ2VvbV9saW5lKHNpemUgPSAxKSArIAogICAgZ2VvbV9wb2ludChzaXplID0gMikgKyAKICAgIGxhYnMoeD0nZHBpIChieSBpbmRleCBjYXNlKScsIHk9J0RWRyByaWNobmVzcycpICsgCiAgICBQbG90VGhlbWUxICsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gJ1NldDInKSArCiAgICAjRGlldGNvbFNjYWxlICsgCiAgICBmYWNldF9ncmlkKC5+cGFpcl9udW1iZXJzLCBzY2FsZXMgPSAnZnJlZScsIHNwYWNlID0gJ2ZyZWUnKQoKcHJpbnQocDQpCgoKZ2dzYXZlKHA0LAogICAgICAgZmlsZW5hbWUgPSBnbHVlKCJ7d2tkaXJ9L0RWR19maWd1cmVzL3NlZ21lbnQub2Jlc2UudG8ub2Jlc2UucmljaG5lc3MucGRmIiksCiAgICAgICB3aWR0aCA9IDEyLAogICAgICAgaGVpZ2h0ID0gNCwgbGltaXRzaXplPUZBTFNFLCB1c2VEaW5nYmF0cyA9IEZBTFNFKQoKZ2dzYXZlKHA0LAogICAgICAgZmlsZW5hbWUgPSBnbHVlKCJ7d2tkaXJ9L0RWR19maWd1cmVzL3NlZ21lbnQub2Jlc2UudG8ub2Jlc2UucmljaG5lc3MucG5nIiksCiAgICAgICB3aWR0aCA9MTIsCiAgICAgICBoZWlnaHQgPSA0LCBsaW1pdHNpemU9RkFMU0UpICMsIHVzZURpbmdiYXRzID0gRkFMU0UpCmBgYAoKRW5kIG9mIEthdGUncyBjb2RlCgpXaGljaCBEVkdzIGFyZSBzaGFyZWQgYmV0d2VlbiBzdG9jayBhbmQgaW5kZXg/CmBgYHtyfQpyZXBzX2RmJERWRyA9IHBhc3RlMChyZXBzX2RmJHNlZ21lbnQsIl8iLHJlcHNfZGYkRFZHX2dyb3VwKQoKRjE3X3N0b2NrID0gZmlsdGVyKHJlcHNfZGYgLGluZl9yb3V0ZSA9PSAiQ29udHJvbCIsIGNvaG9ydCA9PSAiRjE3IikKRjE3X3N0b2NrX2R2ZyA9IHVuaXF1ZShGMTdfc3RvY2skRFZHKQpXMTdfc3RvY2sgPSBmaWx0ZXIocmVwc19kZiAsaW5mX3JvdXRlID09ICJDb250cm9sIiwgY29ob3J0ID09ICJXMTciKQpXMTdfc3RvY2tfZHZnID0gdW5pcXVlKFcxN19zdG9jayREVkcpClNtMThfc3RvY2sgPSBmaWx0ZXIocmVwc19kZiAsaW5mX3JvdXRlID09ICJDb250cm9sIiwgY29ob3J0ID09ICJTbTE4IikKU20xOF9zdG9ja19kdmcgPSB1bmlxdWUoU20xOF9zdG9jayREVkcpClNwMTlfc3RvY2sgPSBmaWx0ZXIocmVwc19kZiAsaW5mX3JvdXRlID09ICJDb250cm9sIiwgY29ob3J0ID09ICJTcDE5IikKU3AxOV9zdG9ja19kdmcgPSB1bmlxdWUoU3AxOV9zdG9jayREVkcpClNwMjBfc3RvY2sgPSBmaWx0ZXIocmVwc19kZiAsaW5mX3JvdXRlID09ICJDb250cm9sIiwgY29ob3J0ID09ICJTcDIwIikKU3AyMF9zdG9ja19kdmcgPSB1bmlxdWUoU3AyMF9zdG9jayREVkcpCgpGMTdfaW5kZXggPSBmaWx0ZXIocmVwc19kZiAsaW5mX3JvdXRlID09ICJJbmRleCIsIGNvaG9ydCA9PSAiRjE3IikKRjE3X2luZGV4X2R2ZyA9IHVuaXF1ZShGMTdfaW5kZXgkRFZHKQpXMTdfaW5kZXggPSBmaWx0ZXIocmVwc19kZiAsaW5mX3JvdXRlID09ICJJbmRleCIsIGNvaG9ydCA9PSAiVzE3IikKVzE3X2luZGV4X2R2ZyA9IHVuaXF1ZShXMTdfaW5kZXgkRFZHKQpTbTE4X2luZGV4ID0gZmlsdGVyKHJlcHNfZGYgLGluZl9yb3V0ZSA9PSAiSW5kZXgiLCBjb2hvcnQgPT0gIlNtMTgiKQpTbTE4X2luZGV4X2R2ZyA9IHVuaXF1ZShTbTE4X2luZGV4JERWRykKU3AxOV9pbmRleCA9IGZpbHRlcihyZXBzX2RmICxpbmZfcm91dGUgPT0gIkluZGV4IiwgY29ob3J0ID09ICJTcDE5IikKU3AxOV9pbmRleF9kdmcgPSB1bmlxdWUoU3AxOV9pbmRleCREVkcpClNwMjBfaW5kZXggPSBmaWx0ZXIocmVwc19kZiAsaW5mX3JvdXRlID09ICJJbmRleCIsIGNvaG9ydCA9PSAiU3AyMCIpClNwMjBfaW5kZXhfZHZnID0gdW5pcXVlKFNwMjBfaW5kZXgkRFZHKQoKRjE3X3NoYXJlZCA9IEYxN19pbmRleCAlPiUgZmlsdGVyKERWRyAlaW4lIEYxN19zdG9ja19kdmcpICU+JSBmaWx0ZXIoKERWRyAlaW4lIEYxN19pbmRleF9kdmcpKSAlPiUgdW5pcXVlKCkKRjE3X2Rlbm92byA9IEYxN19pbmRleCAlPiUgZmlsdGVyKChEVkcgJWluJSBGMTdfaW5kZXhfZHZnKSkgJT4lIGZpbHRlcighKERWRyAlaW4lIEYxN19zdG9ja19kdmcpKSAlPiUgdW5pcXVlKCkKClcxN19zaGFyZWQgPSBXMTdfaW5kZXggJT4lIGZpbHRlcihEVkcgJWluJSBXMTdfc3RvY2tfZHZnKSAlPiUgZmlsdGVyKChEVkcgJWluJSBXMTdfaW5kZXhfZHZnKSkgJT4lIHVuaXF1ZSgpClcxN19kZW5vdm8gPSBXMTdfaW5kZXggJT4lIGZpbHRlcigoRFZHICVpbiUgVzE3X2luZGV4X2R2ZykpICU+JSBmaWx0ZXIoIShEVkcgJWluJSBXMTdfc3RvY2tfZHZnKSkgJT4lIHVuaXF1ZSgpCgpTbTE4X3NoYXJlZCA9IFNtMThfaW5kZXggJT4lIGZpbHRlcihEVkcgJWluJSBTbTE4X3N0b2NrX2R2ZykgJT4lIGZpbHRlcigoRFZHICVpbiUgU20xOF9pbmRleF9kdmcpKSAlPiUgdW5pcXVlKCkKU20xOF9kZW5vdm8gPSBTbTE4X2luZGV4ICU+JSBmaWx0ZXIoKERWRyAlaW4lIFNtMThfaW5kZXhfZHZnKSkgJT4lIGZpbHRlcighKERWRyAlaW4lIFNtMThfc3RvY2tfZHZnKSkgJT4lIHVuaXF1ZSgpCgpTcDE5X3NoYXJlZCA9IFNwMTlfaW5kZXggJT4lIGZpbHRlcihEVkcgJWluJSBTcDE5X3N0b2NrX2R2ZykgJT4lIGZpbHRlcigoRFZHICVpbiUgU3AxOV9pbmRleF9kdmcpKSAlPiUgdW5pcXVlKCkKU3AxOV9kZW5vdm8gPSBTcDE5X2luZGV4ICU+JSBmaWx0ZXIoKERWRyAlaW4lIFNwMTlfaW5kZXhfZHZnKSkgJT4lIGZpbHRlcighKERWRyAlaW4lIFNwMTlfc3RvY2tfZHZnKSkgJT4lIHVuaXF1ZSgpCgpTcDIwX3NoYXJlZCA9IFNwMjBfaW5kZXggJT4lIGZpbHRlcihEVkcgJWluJSBTcDIwX3N0b2NrX2R2ZykgJT4lIGZpbHRlcigoRFZHICVpbiUgU3AyMF9pbmRleF9kdmcpKSAlPiUgdW5pcXVlKCkgIyBzdGlsbCBub3Qgd29ya2luZwpTcDIwX2Rlbm92byA9IFNwMjBfaW5kZXggJT4lIGZpbHRlcigoRFZHICVpbiUgU3AyMF9pbmRleF9kdmcpKSAlPiUgZmlsdGVyKCEoRFZHICVpbiUgU3AyMF9zdG9ja19kdmcpKSAlPiUgdW5pcXVlKCkgIyBzdGlsbCBub3Qgd29ya2luZwoKc3RvY2tfc2hhcmVkID0gcmJpbmQoRjE3X3NoYXJlZCxXMTdfc2hhcmVkLFNtMThfc2hhcmVkLFNwMTlfc2hhcmVkLFNwMjBfc2hhcmVkKQppbmRleF91bmlxdWUgPSByYmluZChGMTdfZGVub3ZvLFcxN19kZW5vdm8sU20xOF9kZW5vdm8sU3AxOV9kZW5vdm8sU3AyMF9kZW5vdm8pCmBgYAoKYGBge3J9CnN0b2NrX29iZXNlID0gZmlsdGVyKHN0b2NrX3NoYXJlZCwgZGlldCA9PSAiT2Jlc2UiKSAKb19kdmcgPSB1bmlxdWUoc3RvY2tfb2Jlc2UkRFZHKQoKc3RvY2tfbGVhbiA9IGZpbHRlcihzdG9ja19zaGFyZWQsIGRpZXQgPT0gIkxlYW4iKSAKbF9kdmcgPSB1bmlxdWUoc3RvY2tfbGVhbiREVkcpCgpzdG9ja19kdmcgPC0gbGlzdChPYmVzZSA9IG9fZHZnLCBMZWFuID0gbF9kdmcpCgpTdG9ja0RWR3MgPSBnZ1Zlbm5EaWFncmFtKHN0b2NrX2R2ZykKcHJpbnQoU3RvY2tEVkdzKQpnZ3NhdmUoU3RvY2tEVkdzLCBmaWxlID0gIlN0b2NrRFZHcy5wZGYiLCBwYXRoID0gc2F2ZWl0ZGlyKQoKU2hvY2tTaGFyZWREVkdzID0gZ2dwbG90KHN0b2NrX3NoYXJlZCwgYWVzKHggPSBkcGksIHkgPSBEVkcpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gRFZHKSkgKwogIGZhY2V0X2dyaWQofnNlZ21lbnQpICsKICBQbG90VGhlbWUxCnByaW50KFNob2NrU2hhcmVkRFZHcykKZ2dzYXZlKFNob2NrU2hhcmVkRFZHcywgZmlsZSA9ICJTaG9ja1NoYXJlZERWR3MucGRmIiwgcGF0aCA9IHNhdmVpdGRpcikKYGBgCkFyZSB0aGVyZSBkaWV0LXNwZWNpZmljIERWR3MgaW4gaW5kZXggZmVycmV0cz8KYGBge3J9CmluZGV4X29iZXNlID0gZmlsdGVyKGluZGV4X3VuaXF1ZSwgZGlldCA9PSAiT2Jlc2UiKSAKb19kdmcgPSB1bmlxdWUoaW5kZXhfb2Jlc2UkRFZHKQoKaW5kZXhfbGVhbiA9IGZpbHRlcihpbmRleF91bmlxdWUsIGRpZXQgPT0gIkxlYW4iKSAKbF9kdmcgPSB1bmlxdWUoaW5kZXhfbGVhbiREVkcpCgpkaWV0X2R2ZyA8LSBsaXN0KE9iZXNlID0gb19kdmcsIExlYW4gPSBsX2R2ZykKCkRpZXRVbmlxdWVEVkdzID0gZ2dWZW5uRGlhZ3JhbShkaWV0X2R2ZykKcHJpbnQoRGlldFVuaXF1ZURWR3MpCmdnc2F2ZShEaWV0VW5pcXVlRFZHcywgZmlsZSA9ICJEaWV0VW5pcXVlRFZHcy5wZGYiLCBwYXRoID0gc2F2ZWl0ZGlyKQpgYGAKClB1bGxpbmcgb3V0IGRpZXQtc3BlY2lmaWMgRFZHcwpgYGB7cn0KbGVhbiA9IGluZGV4X2xlYW4gJT4lIAogIGZpbHRlcihEVkcgJWluJSBsX2R2ZykgJT4lIAogIGZpbHRlcighKERWRyAlaW4lIG9fZHZnKSkgJT4lCiAgdW5pcXVlKCkKCmxlYW4gPSBsZWFuICU+JQogIGdyb3VwX2J5KERWRykgJT4lIAogIG11dGF0ZShjb3VudCA9IDEsIHRvdGFsc2FtcCA9IHN1bShjb3VudCkpCgptdWx0X2xlYW4gPSBmaWx0ZXIobGVhbiwgdG90YWxzYW1wID4gMSkgJT4lIAogIHVuaXF1ZSgpCgpvYmVzZSA9IGluZGV4X3VuaXF1ZSAlPiUgCiAgZmlsdGVyKChEVkcgJWluJSBvX2R2ZykpICU+JQogIGZpbHRlcighKERWRyAlaW4lIGxfZHZnKSkgJT4lIAogIHVuaXF1ZSgpCgpvYmVzZSA9IG9iZXNlICU+JQogIGdyb3VwX2J5KERWRykgJT4lIAogIG11dGF0ZShjb3VudCA9IDEsIHRvdGFsc2FtcCA9IHN1bShjb3VudCkpCgptdWx0X29iZXNlID0gZmlsdGVyKG9iZXNlLCB0b3RhbHNhbXAgPiAxKSAlPiUgCiAgdW5pcXVlKCkKYGBgCgpgYGB7cn0KbGVhbl91bmlxdWVzID0gbGVhbiAlPiUKICB1bmdyb3VwKCkgJT4lIAogIHNlbGVjdChzZWdtZW50LERWR19ncm91cCxHcm91cEJvdW5kYXJpZXMsdG90YWxzYW1wKSAlPiUgCiAgdW5pcXVlKCkgJT4lIAogIGFycmFuZ2UoZGVzYyh0b3RhbHNhbXApKQoKb2Jlc2VfdW5pcXVlcyA9IG9iZXNlICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgc2VsZWN0KHNlZ21lbnQsRFZHX2dyb3VwLEdyb3VwQm91bmRhcmllcyx0b3RhbHNhbXApICU+JSAKICB1bmlxdWUoKSAlPiUgCiAgYXJyYW5nZShkZXNjKHRvdGFsc2FtcCkpCmBgYAoKYGBge3J9CmxlYW5fRFZHX3NpemVzID0gbGVhbiAlPiUgdW5ncm91cCAlPiUgc2VsZWN0KERWRyxEVkdfZ3JvdXAsIERlbGV0aW9uU2l6ZSwgTmV3U3RhcnQsIE5ld0VuZCwgZGlldCkgJT4lIAogIHVuaXF1ZSgpICU+JSAKICBhcnJhbmdlKGRlc2MoRGVsZXRpb25TaXplKSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBmYWN0b3IoRFZHLCBsZXZlbHMgPSB1bmlxdWUoRFZHKSkpCgpnZ3Bsb3QobGVhbl9EVkdfc2l6ZXMsIGFlcyh4ID0gRGVsZXRpb25TaXplLCB5ID0gbmFtZSkpICsKICBnZW9tX2NvbCgpICsKICAjZmFjZXRfZ3JpZChzZWdtZW50fnN0cmFpbikgKwogIFBsb3RUaGVtZTEKI2dnc2F2ZSgidGVzdF9kdmcucGRmIiwgYSwgcGF0aCA9IHNhdmVpdGRpciwgaGVpZ2h0ID0gMzAsIHdpZHRoID0gNSkKCmxlYW5fRFZHX3NpemVzX3Bsb3QgPSBnZ3Bsb3QobGVhbl9EVkdfc2l6ZXMsIGFlcyh4ID0gTmV3U3RhcnQsIHhlbmQgPSBOZXdFbmQsIHkgPSBuYW1lLCB5ZW5kID0gbmFtZSwgY29sb3IgPSBkaWV0KSkgKwogIGdlb21fc2VnbWVudCgpICsKICAjZmFjZXRfZ3JpZChzZWdtZW50fnN0cmFpbikgKwogIFBsb3RUaGVtZTEgICsKICBEaWV0Y29sU2NhbGUKcHJpbnQobGVhbl9EVkdfc2l6ZXNfcGxvdCkKZ2dzYXZlKCJsZWFuX0RWR19zaXplc19wbG90LnBkZiIsbGVhbl9EVkdfc2l6ZXNfcGxvdCwgcGF0aCA9IHNhdmVpdGRpciwgaGVpZ2h0ID0gMTAsIHdpZHRoID0gMTApCgpsZWFuX0RWR19zaXplX3NlZyA9IGxlYW4gJT4lIHVuZ3JvdXAgJT4lIHNlbGVjdChEVkcsRFZHX2dyb3VwLCBEZWxldGlvblNpemUsIE5ld1N0YXJ0LCBOZXdFbmQsIHNlZ21lbnQsZGlldCkgJT4lIAogIHVuaXF1ZSgpICU+JSAKICBhcnJhbmdlKGRlc2Moc2VnbWVudCksZGVzYyhEZWxldGlvblNpemUpKSAlPiUKICBtdXRhdGUobmFtZSA9IGZhY3RvcihEVkcsIGxldmVscyA9IHVuaXF1ZShEVkcpKSkKCmxlYW5fRFZHX3NpemVfc2VnX3Bsb3QgPSBnZ3Bsb3QobGVhbl9EVkdfc2l6ZV9zZWcsIGFlcyh4ID0gTmV3U3RhcnQsIHhlbmQgPSBOZXdFbmQsIHkgPSBuYW1lLCB5ZW5kID0gbmFtZSwgY29sb3IgPSBkaWV0KSkgKwogIGdlb21fc2VnbWVudCgpICsKICBmYWNldF9ncmlkKH5zZWdtZW50KSArCiAgUGxvdFRoZW1lMSArCiAgRGlldGNvbFNjYWxlCnByaW50KGxlYW5fRFZHX3NpemVfc2VnX3Bsb3QpCmdnc2F2ZSgibGVhbl9EVkdfc2l6ZV9zZWdfcGxvdC5wZGYiLGxlYW5fRFZHX3NpemVfc2VnX3Bsb3QscGF0aCA9IHNhdmVpdGRpciwgaGVpZ2h0ID0gMTAsIHdpZHRoID0gMTApCmBgYAoKYGBge3J9Cm9iZXNlX0RWR19zaXplcyA9IG9iZXNlICU+JSB1bmdyb3VwICU+JSBzZWxlY3QoRFZHLERWR19ncm91cCwgRGVsZXRpb25TaXplLCBOZXdTdGFydCwgTmV3RW5kLCBkaWV0KSAlPiUgCiAgdW5pcXVlKCkgJT4lIAogIGFycmFuZ2UoZGVzYyhEZWxldGlvblNpemUpKSAlPiUKICBtdXRhdGUobmFtZSA9IGZhY3RvcihEVkcsIGxldmVscyA9IHVuaXF1ZShEVkcpKSkKCmdncGxvdChvYmVzZV9EVkdfc2l6ZXMsIGFlcyh4ID0gRGVsZXRpb25TaXplLCB5ID0gbmFtZSkpICsKICBnZW9tX2NvbCgpICsKICAjZmFjZXRfZ3JpZChzZWdtZW50fnN0cmFpbikgKwogIFBsb3RUaGVtZTEgCiNnZ3NhdmUoInRlc3RfZHZnLnBkZiIsIGEsIHBhdGggPSBzYXZlaXRkaXIsIGhlaWdodCA9IDMwLCB3aWR0aCA9IDUpCgpvYmVzZV9EVkdfc2l6ZXNfcGxvdCA9IGdncGxvdChvYmVzZV9EVkdfc2l6ZXMsIGFlcyh4ID0gTmV3U3RhcnQsIHhlbmQgPSBOZXdFbmQsIHkgPSBuYW1lLCB5ZW5kID0gbmFtZSwgY29sb3IgPSBkaWV0KSkgKwogIGdlb21fc2VnbWVudCgpICsKICAjZmFjZXRfZ3JpZChzZWdtZW50fnN0cmFpbikgKwogIFBsb3RUaGVtZTEgKwogIERpZXRjb2xTY2FsZQpwcmludChvYmVzZV9EVkdfc2l6ZXNfcGxvdCkKZ2dzYXZlKCJvYmVzZV9EVkdfc2l6ZXNfcGxvdC5wZGYiLG9iZXNlX0RWR19zaXplc19wbG90LCBwYXRoID0gc2F2ZWl0ZGlyLCBoZWlnaHQgPSAxMCwgd2lkdGggPSAxMCkKCm9iZXNlX0RWR19zaXplX3NlZyA9IG9iZXNlICU+JSB1bmdyb3VwICU+JSBzZWxlY3QoRFZHLERWR19ncm91cCwgRGVsZXRpb25TaXplLCBOZXdTdGFydCwgTmV3RW5kLCBzZWdtZW50LGRpZXQpICU+JSAKICB1bmlxdWUoKSAlPiUgCiAgYXJyYW5nZShkZXNjKHNlZ21lbnQpLGRlc2MoRGVsZXRpb25TaXplKSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBmYWN0b3IoRFZHLCBsZXZlbHMgPSB1bmlxdWUoRFZHKSkpCgpvYmVzZV9EVkdfc2l6ZV9zZWdfcGxvdCA9IGdncGxvdChvYmVzZV9EVkdfc2l6ZV9zZWcsIGFlcyh4ID0gTmV3U3RhcnQsIHhlbmQgPSBOZXdFbmQsIHkgPSBuYW1lLCB5ZW5kID0gbmFtZSwgY29sb3IgPSBkaWV0KSkgKwogIGdlb21fc2VnbWVudCgpICsKICBmYWNldF9ncmlkKH5zZWdtZW50KSArCiAgUGxvdFRoZW1lMSAgKwogIERpZXRjb2xTY2FsZQpwcmludChvYmVzZV9EVkdfc2l6ZV9zZWdfcGxvdCkKZ2dzYXZlKCJvYmVzZV9EVkdfc2l6ZV9zZWdfcGxvdC5wZGYiLG9iZXNlX0RWR19zaXplX3NlZ19wbG90LCBwYXRoID0gc2F2ZWl0ZGlyLCBoZWlnaHQgPSAxMCwgd2lkdGggPSAxMCkKCmBgYAoKQXJlIERWR3MgdHJhbnNtaXR0ZWQ/CmBgYHtyfQpkdmdfZGYgPSBzZWxlY3QocmVwc19kZiwgZmVycmV0X2RheSwgZmVycmV0X2lkLCBkcGksIGRpZXQsIGluZl9yb3V0ZSwgc2VnbWVudCwgRFZHX2dyb3VwLCBHcm91cEJvdW5kYXJpZXMsIHBhaXJfZGlldHMsIHBhaXJfbnVtYmVycykgJT4lCiAgdW5ncm91cCgpICU+JQogIHVuaXF1ZSgpCmR2Z19kZiRzZWdfZHZnID0gcGFzdGUwKGR2Z19kZiRzZWdtZW50LCJfIixkdmdfZGYkRFZHX2dyb3VwKQoKaW5kZXggPSBmaWx0ZXIoZHZnX2RmLCBpbmZfcm91dGUgPT0gIkluZGV4IikgJT4lIHVuaXF1ZSgpCmZpcnN0X3RpbWUgPSBjKCIxNzk0X2QwNCIsIjE3OTdfZDAyIiwiMTkxM19kMDYiLCIxOTE0X2QwNiIsIjE5ODBfZDAyIiwiMTk4MV9kMTAiLCIxOTg2X2QxMCIsIjIyMzFfZDA2IiwiMjIzMl9kMDIiLCIyMjM5X2QwMiIpCmVhcmx5X3RpbWUgPSBjKCIxNzk0X2QwNCIsIjE3OTdfZDAyIiwiMTk4MF9kMDIiLCIyMjMyX2QwMiIsIjIyMzlfZDAyIikKZGlyZWN0ID0gZmlsdGVyKGR2Z19kZiwgZmVycmV0X2RheSAlaW4lIGZpcnN0X3RpbWUpICU+JSB1bmlxdWUoKQogCnNhbXBsZXMgPSB1bmlxdWUoaW5kZXgkZmVycmV0X2RheSkKICAKZHZnX3RyYW5zbWl0dGVkID0gZGF0YS5mcmFtZSgpCiAgCmZvcihpIGluIHNhbXBsZXMpewogIHByaW50KGkpCiAgCiAgbiA9IGZpbHRlcihpbmRleCwgZmVycmV0X2RheSA9PSBpKQogIHBhcnRuZXIgPSB1bmlxdWUobiRwYWlyX251bWJlcnMpCiAgZCA9IGZpbHRlcihkaXJlY3QsIHBhaXJfbnVtYmVycyAlaW4lIHBhcnRuZXIpCiAgCiAgaWYobnJvdyhkKSA+IDApewogICAgCiAgICBzID0gdW5pcXVlKGQkZmVycmV0X2RheSkKICAgIHByaW50KHMpCiAgCiAgICBjb21wID0gbWVyZ2UobiwgZCwgYnkgPSBjKCJwYWlyX2RpZXRzIiwicGFpcl9udW1iZXJzIiwicGFpciIsInNlZ21lbnQiLCJzZWdfZHZnIiwiRFZHX2dyb3VwIiwiR3JvdXBCb3VuZGFyaWVzIiksIGFsbC54ID0gVFJVRSkgJT4lCiAgICAgIGNvdW50KHBhaXJfbnVtYmVycyxmZXJyZXRfZGF5LngsIGZlcnJldF9kYXkueSkKICAgIGNvbG5hbWVzKGNvbXApID0gYygicGFpcl9udW1iZXJzIiwiSW5kZXgiLCJDb250YWN0IiwiY291bnQiKQogICAgIAogICAgZHZnX3RyYW5zbWl0dGVkID0gcmJpbmQoZHZnX3RyYW5zbWl0dGVkLCBjb21wKQogICAKICB9ZWxzZShwcmludCgiTm8gdHJhbnNtaXNzaW9uIikpCiAgCn0KCiNkdmdfdHJhbnNtaXR0ZWQgPSBkdmdfdHJhbnNtaXR0ZWQgJT4lIAojICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY29udGFjdCwgdmFsdWVzX2Zyb20gPSBjb3VudCkKYGBgCgpgYGB7cn0KIGNvbnRhY3RfZHZncyA9IGZpbHRlcihkdmdfZGYsIGluZl9yb3V0ZSA9PSAiSW5kZXgiKSAlPiUgY291bnQoZmVycmV0X2lkLGRwaSxkaWV0KSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHggPSBkcGksIHkgPSBuLCBjb2xvciA9IGRpZXQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gZmVycmV0X2lkKSkgKwogIGZhY2V0X2dyaWQofmZlcnJldF9pZCkgKwogIHlsYWIoIkRWRyByaWNobmVzcyIpICsKICB4bGFiKCJEUEkiKSArCiAgUGxvdFRoZW1lMSArCiAgRGlldGNvbFNjYWxlCnByaW50KGNvbnRhY3RfZHZncykKZ2dzYXZlKGNvbnRhY3RfZHZncywgZmlsZSA9ICJjb250YWN0X2R2Z3MucGRmIiwgcGF0aCA9IHNhdmVpdGRpcikKYGBgCg==